Also escape characters >=0x80 within the wineregistry savefile.
[wine/testsucceed.git] / misc / registry.c
blobfc3fd31ddcad5ba320c7866811952e09e468b417
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
12 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #ifdef HAVE_SYS_ERRNO_H
28 #include <sys/errno.h>
29 #endif
30 #include <sys/types.h>
31 #include <sys/fcntl.h>
32 #include <sys/stat.h>
33 #include <assert.h>
34 #include <time.h>
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wine/winbase16.h"
38 #include "wine/winestring.h"
39 #include "winerror.h"
40 #include "file.h"
41 #include "heap.h"
42 #include "debugtools.h"
43 #include "xmalloc.h"
44 #include "options.h"
45 #include "winreg.h"
46 #include "winversion.h"
48 DECLARE_DEBUG_CHANNEL(reg)
49 DECLARE_DEBUG_CHANNEL(string)
51 static void REGISTRY_Init(void);
52 /* FIXME: following defines should be configured global ... */
54 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
55 #define WINE_PREFIX "/.wine"
56 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
57 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
59 /* relative in ~user/.wine/ : */
60 #define SAVE_CURRENT_USER "user.reg"
61 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
62 #define SAVE_LOCAL_MACHINE "system.reg"
64 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
65 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
67 /* one value of a key */
68 typedef struct tagKEYVALUE
70 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
71 DWORD type; /* type of value */
72 DWORD len; /* length of data in BYTEs */
73 DWORD lastmodified; /* time of seconds since 1.1.1970 */
74 LPBYTE data; /* content, may be strings, binaries, etc. */
75 } KEYVALUE,*LPKEYVALUE;
77 /* a registry key */
78 typedef struct tagKEYSTRUCT
80 LPWSTR keyname; /* name of THIS key (UNICODE) */
81 DWORD flags; /* flags. */
82 LPWSTR class;
83 /* values */
84 DWORD nrofvalues; /* nr of values in THIS key */
85 LPKEYVALUE values; /* values in THIS key */
86 /* key management pointers */
87 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
88 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
89 } KEYSTRUCT, *LPKEYSTRUCT;
92 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
93 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
94 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
95 static KEYSTRUCT *key_users=NULL; /* all users? */
97 /* dynamic, not saved */
98 static KEYSTRUCT *key_performance_data=NULL;
99 static KEYSTRUCT *key_current_config=NULL;
100 static KEYSTRUCT *key_dyn_data=NULL;
102 /* what valuetypes do we need to convert? */
103 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
106 static struct openhandle {
107 LPKEYSTRUCT lpkey;
108 HKEY hkey;
109 REGSAM accessmask;
110 } *openhandles=NULL;
111 static int nrofopenhandles=0;
112 /* Starts after 1 because 0,1 are reserved for Win16 */
113 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
114 HKEYs for remote registry access */
115 static int currenthandle=2;
119 * QUESTION
120 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
121 * If so, can we remove them?
122 * ANSWER
123 * No, the memory handling functions are called very often in here,
124 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
125 * loading 100 times slower. -MM
127 static LPWSTR strdupA2W(LPCSTR src)
129 if(src) {
130 LPWSTR dest=xmalloc(2*strlen(src)+2);
131 lstrcpyAtoW(dest,src);
132 return dest;
134 return NULL;
137 static LPWSTR strdupW(LPCWSTR a) {
138 LPWSTR b;
139 int len;
141 if(a) {
142 len=sizeof(WCHAR)*(lstrlenW(a)+1);
143 b=(LPWSTR)xmalloc(len);
144 memcpy(b,a,len);
145 return b;
147 return NULL;
150 LPWSTR strcvtA2W(LPCSTR src, int nchars)
153 LPWSTR dest = xmalloc (2 * nchars + 2);
155 lstrcpynAtoW(dest,src,nchars+1);
156 dest[nchars] = 0;
157 return dest;
160 * we need to convert A to W with '\0' in strings (MULTI_SZ)
163 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
164 { LPWSTR p = dst;
166 TRACE_(reg)("\"%s\" %i\n",src, n);
168 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
170 return dst;
172 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
173 { LPSTR p = dst;
175 TRACE_(string)("L\"%s\" %i\n",debugstr_w(src), n);
177 while (n-- > 0) *p++ = (CHAR)*src++;
179 return dst;
182 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
184 if (TRACE_ON(reg) && lpbData)
186 switch(key->type)
188 case REG_EXPAND_SZ:
189 case REG_SZ:
190 TRACE_(reg)(" Value %s, Data(sz)=%s\n",
191 debugstr_w(key->name),
192 debugstr_w((LPCWSTR)lpbData));
193 break;
195 case REG_DWORD:
196 TRACE_(reg)(" Value %s, Data(dword)=0x%08lx\n",
197 debugstr_w(key->name),
198 (DWORD)*lpbData);
199 break;
201 case REG_MULTI_SZ:
203 int i;
204 LPCWSTR ptr = (LPCWSTR)lpbData;
205 for (i=0;ptr[0];i++)
207 TRACE_(reg)(" Value %s, MULTI_SZ(%i=%s)\n",
208 debugstr_w(key->name),
210 debugstr_w(ptr));
212 ptr += lstrlenW(ptr)+1;
215 break;
217 default:
219 char szTemp[100]; /* 3*32 + 3 + 1 */
220 int i;
221 for ( i = 0; i < key->len ; i++)
223 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
224 if (i>=31)
226 sprintf (&(szTemp[i*3+3]),"...");
227 break;
230 TRACE_(reg)(" Value %s, Data(raw)=(%s)\n",
231 debugstr_w(key->name),
232 szTemp);
234 } /* switch */
235 } /* if */
239 /******************************************************************************
240 * is_standard_hkey [Internal]
241 * Determines if a hkey is a standard key
243 static BOOL is_standard_hkey( HKEY hkey )
245 switch(hkey) {
246 case 0x00000000:
247 case 0x00000001:
248 case HKEY_CLASSES_ROOT:
249 case HKEY_CURRENT_CONFIG:
250 case HKEY_CURRENT_USER:
251 case HKEY_LOCAL_MACHINE:
252 case HKEY_USERS:
253 case HKEY_PERFORMANCE_DATA:
254 case HKEY_DYN_DATA:
255 return TRUE;
256 default:
257 return FALSE;
261 /******************************************************************************
262 * add_handle [Internal]
264 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
266 int i;
268 TRACE_(reg)("(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
269 /* Check for duplicates */
270 for (i=0;i<nrofopenhandles;i++) {
271 if (openhandles[i].lpkey==lpkey) {
272 /* This is not really an error - the user is allowed to create
273 two (or more) handles to the same key */
274 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
276 if (openhandles[i].hkey==hkey) {
277 WARN_(reg)("Adding handle %x twice\n",hkey);
280 openhandles=xrealloc( openhandles,
281 sizeof(struct openhandle)*(nrofopenhandles+1));
283 openhandles[i].lpkey = lpkey;
284 openhandles[i].hkey = hkey;
285 openhandles[i].accessmask = accessmask;
286 nrofopenhandles++;
290 /******************************************************************************
291 * get_handle [Internal]
293 * RETURNS
294 * Success: Pointer to key
295 * Failure: NULL
297 static LPKEYSTRUCT get_handle( HKEY hkey )
299 int i;
301 for (i=0; i<nrofopenhandles; i++)
302 if (openhandles[i].hkey == hkey)
303 return openhandles[i].lpkey;
304 WARN_(reg)("Could not find handle 0x%x\n",hkey);
305 return NULL;
309 /******************************************************************************
310 * remove_handle [Internal]
312 * PARAMS
313 * hkey [I] Handle of key to remove
315 * RETURNS
316 * Success: ERROR_SUCCESS
317 * Failure: ERROR_INVALID_HANDLE
319 static DWORD remove_handle( HKEY hkey )
321 int i;
323 for (i=0;i<nrofopenhandles;i++)
324 if (openhandles[i].hkey==hkey)
325 break;
327 if (i == nrofopenhandles) {
328 WARN_(reg)("Could not find handle 0x%x\n",hkey);
329 return ERROR_INVALID_HANDLE;
332 memcpy( openhandles+i,
333 openhandles+i+1,
334 sizeof(struct openhandle)*(nrofopenhandles-i-1)
336 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
337 nrofopenhandles--;
338 return ERROR_SUCCESS;
341 /******************************************************************************
342 * lookup_hkey [Internal]
344 * Just as the name says. Creates the root keys on demand, so we can call the
345 * Reg* functions at any time.
347 * RETURNS
348 * Success: Pointer to key structure
349 * Failure: NULL
351 #define ADD_ROOT_KEY(xx) \
352 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
353 memset(xx,'\0',sizeof(KEYSTRUCT));\
354 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
356 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
358 switch (hkey) {
359 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
360 * some programs. Do not remove those cases. -MM
362 case 0x00000000:
363 case 0x00000001:
364 case HKEY_CLASSES_ROOT:
366 if (!key_classes_root)
368 HKEY cl_r_hkey;
370 /* calls lookup_hkey recursively, TWICE */
371 if ( RegCreateKey16(
372 HKEY_LOCAL_MACHINE,
373 "SOFTWARE\\Classes",
374 &cl_r_hkey) != ERROR_SUCCESS)
376 ERR_(reg)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
377 exit(1);
380 key_classes_root = lookup_hkey(cl_r_hkey);
382 return key_classes_root;
385 case HKEY_CURRENT_USER:
386 if (!key_current_user) {
387 ADD_ROOT_KEY(key_current_user);
389 return key_current_user;
391 case HKEY_LOCAL_MACHINE:
392 if (!key_local_machine) {
393 ADD_ROOT_KEY(key_local_machine);
394 REGISTRY_Init();
396 return key_local_machine;
398 case HKEY_USERS:
399 if (!key_users) {
400 ADD_ROOT_KEY(key_users);
402 return key_users;
404 case HKEY_PERFORMANCE_DATA:
405 if (!key_performance_data) {
406 ADD_ROOT_KEY(key_performance_data);
408 return key_performance_data;
410 case HKEY_DYN_DATA:
411 if (!key_dyn_data) {
412 ADD_ROOT_KEY(key_dyn_data);
414 return key_dyn_data;
416 case HKEY_CURRENT_CONFIG:
417 if (!key_current_config) {
418 ADD_ROOT_KEY(key_current_config);
420 return key_current_config;
422 default:
423 return get_handle(hkey);
426 /*NOTREACHED*/
431 * recursively searches for lpkey_to_find in the root key branch
432 * given in lpcurrkey.
434 static int subkey_found(LPKEYSTRUCT lpcurrkey, LPKEYSTRUCT lpkey_to_find)
436 while (lpcurrkey)
438 if (lpcurrkey == lpkey_to_find)
439 return 1;
440 if (subkey_found(lpcurrkey->nextsub, lpkey_to_find))
441 return 1;
443 lpcurrkey = lpcurrkey->next;
446 TRACE_(reg)("No key found in this root key branch\n");
447 return 0;
452 * finds the corresponding root key for a sub key, i.e. e.g. HKEY_CLASSES_ROOT.
454 static HKEY find_root_key(LPKEYSTRUCT lpkey)
456 typedef struct tagROOT_KEYS {
457 KEYSTRUCT *lpkey;
458 HKEY hkey;
459 } ROOT_KEYS;
460 ROOT_KEYS root_keys[4];
461 int i;
463 root_keys[0].lpkey = key_classes_root;
464 root_keys[0].hkey = HKEY_CLASSES_ROOT;
465 root_keys[1].lpkey = key_current_user;
466 root_keys[1].hkey = HKEY_CURRENT_USER;
467 root_keys[2].lpkey = key_local_machine;
468 root_keys[2].hkey = HKEY_LOCAL_MACHINE;
469 root_keys[3].lpkey = key_users;
470 root_keys[3].hkey = HKEY_USERS;
472 for (i=0; i<4;i++)
474 if (subkey_found(root_keys[i].lpkey, lpkey))
475 return root_keys[i].hkey;
477 ERR_(reg)("Didn't find corresponding root key entry ! Search strategy broken ??\n");
478 return 0;
479 #undef ROOT_KEYS
481 #undef ADD_ROOT_KEY
482 /* so we don't accidently access them ... */
483 #define key_current_config NULL NULL
484 #define key_current_user NULL NULL
485 #define key_users NULL NULL
486 #define key_local_machine NULL NULL
487 #define key_classes_root NULL NULL
488 #define key_dyn_data NULL NULL
489 #define key_performance_data NULL NULL
491 /******************************************************************************
492 * split_keypath [Internal]
493 * splits the unicode string 'wp' into an array of strings.
494 * the array is allocated by this function.
495 * Free the array using FREE_KEY_PATH
497 * PARAMS
498 * wp [I] String to split up
499 * wpv [O] Array of pointers to strings
500 * wpc [O] Number of components
502 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
504 int i,j,len;
505 LPWSTR ws;
507 TRACE_(reg)("(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
509 ws = HEAP_strdupW( SystemHeap, 0, wp );
511 /* We know we have at least one substring */
512 *wpc = 1;
514 /* Replace each backslash with NULL, and increment the count */
515 for (i=0;ws[i];i++) {
516 if (ws[i]=='\\') {
517 ws[i]=0;
518 (*wpc)++;
522 len = i;
524 /* Allocate the space for the array of pointers, leaving room for the
525 NULL at the end */
526 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
527 (*wpv)[0]= ws;
529 /* Assign each pointer to the appropriate character in the string */
530 j = 1;
531 for (i=1;i<len;i++)
532 if (ws[i-1]==0) {
533 (*wpv)[j++]=ws+i;
534 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
537 (*wpv)[j]=NULL;
539 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
544 /******************************************************************************
545 * REGISTRY_Init [Internal]
546 * Registry initialisation, allocates some default keys.
548 static void REGISTRY_Init(void) {
549 HKEY hkey;
550 char buf[200];
552 TRACE_(reg)("(void)\n");
554 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
555 RegCloseKey(hkey);
557 /* This was an Open, but since it is called before the real registries
558 are loaded, it was changed to a Create - MTB 980507*/
559 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
560 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
561 RegCloseKey(hkey);
563 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
564 * CurrentVersion
565 * CurrentBuildNumber
566 * CurrentType
567 * string RegisteredOwner
568 * string RegisteredOrganization
571 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
572 * string SysContact
573 * string SysLocation
574 * SysServices
576 if (-1!=gethostname(buf,200)) {
577 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
578 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
579 RegCloseKey(hkey);
584 /************************ SAVE Registry Function ****************************/
586 #define REGISTRY_SAVE_VERSION 0x00000001
588 /* Registry saveformat:
589 * If you change it, increase above number by 1, which will flush
590 * old registry database files.
592 * Global:
593 * "WINE REGISTRY Version %d"
594 * subkeys....
595 * Subkeys:
596 * keyname
597 * valuename=lastmodified,type,data
598 * ...
599 * subkeys
600 * ...
601 * keyname,valuename,stringdata:
602 * the usual ascii characters from 0x00-0xff (well, not 0x00)
603 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
604 * ( "=\\\t" escaped in \uXXXX form.)
605 * type,lastmodified:
606 * int
608 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
610 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
611 * SaveOnlyUpdatedKeys=yes
614 /******************************************************************************
615 * _save_check_tainted [Internal]
617 static int _save_check_tainted( LPKEYSTRUCT lpkey )
619 int tainted;
621 if (!lpkey)
622 return 0;
623 if (lpkey->flags & REG_OPTION_TAINTED)
624 tainted = 1;
625 else
626 tainted = 0;
627 while (lpkey) {
628 if (_save_check_tainted(lpkey->nextsub)) {
629 lpkey->flags |= REG_OPTION_TAINTED;
630 tainted = 1;
632 lpkey = lpkey->next;
634 return tainted;
637 /******************************************************************************
638 * _save_USTRING [Internal]
640 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
642 LPWSTR s;
643 int doescape;
645 if (wstr==NULL)
646 return;
647 s=wstr;
648 while (*s) {
649 doescape=0;
650 if (*s>0x7f)
651 doescape = 1;
652 if (*s=='\n')
653 doescape = 1;
654 if (escapeeq && *s=='=')
655 doescape = 1;
656 if (*s=='\\')
657 fputc(*s,F); /* if \\ then put it twice. */
658 if (doescape)
659 fprintf(F,"\\u%04x",*((unsigned short*)s));
660 else
661 fputc(*s,F);
662 s++;
666 /******************************************************************************
667 * _savesubkey [Internal]
669 * NOTES
670 * REG_MULTI_SZ is handled as binary (like in win95) (js)
672 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
674 LPKEYSTRUCT lpxkey;
675 int i,tabs,j;
677 lpxkey = lpkey;
678 while (lpxkey) {
679 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
680 (all || (lpxkey->flags & REG_OPTION_TAINTED))
682 for (tabs=level;tabs--;)
683 fputc('\t',F);
684 _save_USTRING(F,lpxkey->keyname,1);
685 fputs("\n",F);
686 for (i=0;i<lpxkey->nrofvalues;i++) {
687 LPKEYVALUE val=lpxkey->values+i;
689 for (tabs=level+1;tabs--;)
690 fputc('\t',F);
691 _save_USTRING(F,val->name,0);
692 fputc('=',F);
693 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
694 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
695 _save_USTRING(F,(LPWSTR)val->data,0);
696 else
697 for (j=0;j<val->len;j++)
698 fprintf(F,"%02x",*((unsigned char*)val->data+j));
699 fputs("\n",F);
701 /* descend recursively */
702 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
703 return 0;
705 lpxkey=lpxkey->next;
707 return 1;
711 /******************************************************************************
712 * _savesubreg [Internal]
714 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
716 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
717 _save_check_tainted(lpkey->nextsub);
718 return _savesubkey(F,lpkey->nextsub,0,all);
722 /******************************************************************************
723 * _savereg [Internal]
725 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
727 FILE *F;
729 F=fopen(fn,"w");
730 if (F==NULL) {
731 WARN_(reg)("Couldn't open %s for writing: %s\n",
732 fn,strerror(errno)
734 return FALSE;
736 if (!_savesubreg(F,lpkey,all)) {
737 fclose(F);
738 unlink(fn);
739 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
740 return FALSE;
742 fclose(F);
743 return TRUE;
747 /******************************************************************************
748 * SHELL_SaveRegistryBranch [Internal]
750 * Saves main registry branch specified by hkey.
752 static void SHELL_SaveRegistryBranch(HKEY hkey, int all)
754 char *fn, *home, *tmp;
756 /* FIXME: does this check apply to all keys written below ? */
757 if (!(home = getenv( "HOME" )))
759 ERR_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
760 return;
763 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
764 if (hkey == HKEY_CLASSES_ROOT)
765 hkey = HKEY_LOCAL_MACHINE;
767 switch (hkey)
769 case HKEY_CURRENT_USER:
771 int usedCfgUser = 0;
773 fn = xmalloc( MAX_PATHNAME_LEN );
774 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "",
775 fn, MAX_PATHNAME_LEN - 1))
777 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
778 usedCfgUser = 1;
780 free (fn);
782 if (usedCfgUser != 1)
784 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
785 strlen(SAVE_CURRENT_USER) + 2 );
786 strcpy(fn,home);
787 strcat(fn,WINE_PREFIX);
789 /* create the directory. don't care about errorcodes. */
790 mkdir(fn,0755); /* drwxr-xr-x */
791 strcat(fn,"/"SAVE_CURRENT_USER);
793 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
794 strcpy(tmp,fn);
795 strcat(tmp,".tmp");
797 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
798 if (-1==rename(tmp,fn)) {
799 perror("rename tmp registry");
800 unlink(tmp);
803 free(tmp);
804 free(fn);
807 break;
808 case HKEY_LOCAL_MACHINE:
810 int usedCfgLM = 0;
811 /* Try first saving according to the defined location in .winerc */
812 fn = xmalloc ( MAX_PATHNAME_LEN);
813 if (PROFILE_GetWineIniString ( "Registry",
814 "LocalMachineFileName", "", fn, MAX_PATHNAME_LEN - 1))
816 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
817 usedCfgLM = 1;
819 free (fn);
821 if ( usedCfgLM != 1)
823 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
824 strlen(SAVE_LOCAL_MACHINE) + 2);
825 strcpy(fn,home);
826 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
828 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
829 strcpy(tmp,fn);
830 strcat(tmp,".tmp");
832 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
833 if (-1==rename(tmp,fn)) {
834 perror("rename tmp registry");
835 unlink(tmp);
838 free(tmp);
839 free(fn);
842 break;
843 case HKEY_USERS:
844 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
845 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
847 strcpy(fn,home);
848 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
850 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
851 strcpy(tmp,fn);strcat(tmp,".tmp");
852 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
853 if (-1==rename(tmp,fn)) {
854 perror("rename tmp registry");
855 unlink(tmp);
858 free(tmp);
859 free(fn);
860 break;
861 default:
862 ERR_(reg)("unknown/invalid key handle !\n");
867 /******************************************************************************
868 * SHELL_SaveRegistry [Internal]
870 void SHELL_SaveRegistry( void )
872 char buf[4];
873 HKEY hkey;
874 int all;
876 TRACE_(reg)("(void)\n");
878 all=0;
879 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
881 strcpy(buf,"yes");
883 else
885 DWORD len,junk,type;
887 len=4;
888 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
889 VAL_SAVEUPDATED,
890 &junk,
891 &type,
892 buf,
893 &len)) || (type!=REG_SZ))
895 strcpy(buf,"yes");
897 RegCloseKey(hkey);
900 if (lstrcmpiA(buf,"yes"))
901 all = 1;
903 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER, all);
904 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE, all);
905 SHELL_SaveRegistryBranch(HKEY_USERS, all);
909 /************************ LOAD Registry Function ****************************/
913 /******************************************************************************
914 * _find_or_add_key [Internal]
916 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
918 LPKEYSTRUCT lpxkey,*lplpkey;
920 if ((!keyname) || (keyname[0]==0)) {
921 free(keyname);
922 return lpkey;
924 lplpkey= &(lpkey->nextsub);
925 lpxkey = *lplpkey;
926 while (lpxkey) {
927 if ( tolower(lpxkey->keyname[0])==tolower(keyname[0]) &&
928 !lstrcmpiW(lpxkey->keyname,keyname)
930 break;
931 lplpkey = &(lpxkey->next);
932 lpxkey = *lplpkey;
934 if (lpxkey==NULL) {
935 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
936 lpxkey = *lplpkey;
937 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
938 lpxkey->keyname = keyname;
939 } else
940 free(keyname);
941 return lpxkey;
944 /******************************************************************************
945 * _find_or_add_value [Internal]
947 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
948 LPBYTE data, DWORD len, DWORD lastmodified )
950 LPKEYVALUE val=NULL;
951 int i;
953 if (name && !*name) {/* empty string equals default (NULL) value */
954 free(name);
955 name = NULL;
958 for (i=0;i<lpkey->nrofvalues;i++) {
959 val=lpkey->values+i;
960 if (name==NULL) {
961 if (val->name==NULL)
962 break;
963 } else {
964 if ( val->name!=NULL &&
965 tolower(val->name[0])==tolower(name[0]) &&
966 !lstrcmpiW(val->name,name)
968 break;
971 if (i==lpkey->nrofvalues) {
972 lpkey->values = xrealloc(
973 lpkey->values,
974 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
976 val=lpkey->values+i;
977 memset(val,'\0',sizeof(KEYVALUE));
978 val->name = name;
979 } else {
980 if (name)
981 free(name);
983 if (val->lastmodified<lastmodified) {
984 val->lastmodified=lastmodified;
985 val->type = type;
987 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
989 data=xmalloc(sizeof(WCHAR));
990 memset(data,0,sizeof(WCHAR));
991 len =sizeof(WCHAR);
994 val->len = len;
995 if (val->data)
996 free(val->data);
997 val->data = data;
998 } else
999 free(data);
1003 /******************************************************************************
1004 * _wine_read_line [Internal]
1006 * reads a line including dynamically enlarging the readbuffer and throwing
1007 * away comments
1009 static int _wine_read_line( FILE *F, char **buf, int *len )
1011 char *s,*curread;
1012 int mylen,curoff;
1014 curread = *buf;
1015 mylen = *len;
1016 **buf = '\0';
1017 while (1) {
1018 while (1) {
1019 s=fgets(curread,mylen,F);
1020 if (s==NULL)
1021 return 0; /* EOF */
1022 if (NULL==(s=strchr(curread,'\n'))) {
1023 /* buffer wasn't large enough */
1024 curoff = strlen(*buf);
1025 *buf = xrealloc(*buf,*len*2);
1026 curread = *buf + curoff;
1027 mylen = *len; /* we filled up the buffer and
1028 * got new '*len' bytes to fill
1030 *len = *len * 2;
1031 } else {
1032 *s='\0';
1033 break;
1036 /* throw away comments */
1037 if (**buf=='#' || **buf==';') {
1038 curread = *buf;
1039 mylen = *len;
1040 continue;
1042 if (s) /* got end of line */
1043 break;
1045 return 1;
1049 /******************************************************************************
1050 * _wine_read_USTRING [Internal]
1052 * converts a char* into a UNICODE string (up to a special char)
1053 * and returns the position exactly after that string
1055 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1057 char *s;
1058 LPWSTR ws;
1060 /* read up to "=" or "\0" or "\n" */
1061 s = buf;
1062 if (*s == '=') {
1063 /* empty string is the win3.1 default value(NULL)*/
1064 *str = NULL;
1065 return s;
1067 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1068 ws = *str;
1069 while (*s && (*s!='\n') && (*s!='=')) {
1070 if (*s!='\\')
1071 *ws++=*((unsigned char*)s++);
1072 else {
1073 s++;
1074 if (!*s) {
1075 /* Dangling \ ... may only happen if a registry
1076 * write was short. FIXME: What do to?
1078 break;
1080 if (*s=='\\') {
1081 *ws++='\\';
1082 s++;
1083 continue;
1085 if (*s!='u') {
1086 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1087 *ws++='\\';
1088 *ws++=*s++;
1089 } else {
1090 char xbuf[5];
1091 int wc;
1093 s++;
1094 memcpy(xbuf,s,4);xbuf[4]='\0';
1095 if (!sscanf(xbuf,"%x",&wc))
1096 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1097 s+=4;
1098 *ws++ =(unsigned short)wc;
1102 *ws = 0;
1103 ws = *str;
1104 if (*ws)
1105 *str = strdupW(*str);
1106 else
1107 *str = NULL;
1108 free(ws);
1109 return s;
1113 /******************************************************************************
1114 * _wine_loadsubkey [Internal]
1116 * NOTES
1117 * It seems like this is returning a boolean. Should it?
1119 * RETURNS
1120 * Success: 1
1121 * Failure: 0
1123 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1124 int *buflen, DWORD optflag )
1126 LPKEYSTRUCT lpxkey;
1127 int i;
1128 char *s;
1129 LPWSTR name;
1131 TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1132 *buflen, optflag);
1134 lpkey->flags |= optflag;
1136 /* Good. We already got a line here ... so parse it */
1137 lpxkey = NULL;
1138 while (1) {
1139 i=0;s=*buf;
1140 while (*s=='\t') {
1141 s++;
1142 i++;
1144 if (i>level) {
1145 if (lpxkey==NULL) {
1146 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1147 return 0;
1149 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1150 continue;
1153 /* let the caller handle this line */
1154 if (i<level || **buf=='\0')
1155 return 1;
1157 /* it can be: a value or a keyname. Parse the name first */
1158 s=_wine_read_USTRING(s,&name);
1160 /* switch() default: hack to avoid gotos */
1161 switch (0) {
1162 default:
1163 if (*s=='\0') {
1164 lpxkey=_find_or_add_key(lpkey,name);
1165 } else {
1166 LPBYTE data;
1167 int len,lastmodified,type;
1169 if (*s!='=') {
1170 WARN_(reg)("Unexpected character: %c\n",*s);
1171 break;
1173 s++;
1174 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1175 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1176 break;
1178 /* skip the 2 , */
1179 s=strchr(s,',');s++;
1180 s=strchr(s,',');s++;
1181 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1182 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1183 if (data)
1184 len = lstrlenW((LPWSTR)data)*2+2;
1185 else
1186 len = 0;
1187 } else {
1188 len=strlen(s)/2;
1189 data = (LPBYTE)xmalloc(len+1);
1190 for (i=0;i<len;i++) {
1191 data[i]=0;
1192 if (*s>='0' && *s<='9')
1193 data[i]=(*s-'0')<<4;
1194 if (*s>='a' && *s<='f')
1195 data[i]=(*s-'a'+'\xa')<<4;
1196 if (*s>='A' && *s<='F')
1197 data[i]=(*s-'A'+'\xa')<<4;
1198 s++;
1199 if (*s>='0' && *s<='9')
1200 data[i]|=*s-'0';
1201 if (*s>='a' && *s<='f')
1202 data[i]|=*s-'a'+'\xa';
1203 if (*s>='A' && *s<='F')
1204 data[i]|=*s-'A'+'\xa';
1205 s++;
1208 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1211 /* read the next line */
1212 if (!_wine_read_line(F,buf,buflen))
1213 return 1;
1215 return 1;
1219 /******************************************************************************
1220 * _wine_loadsubreg [Internal]
1222 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1224 int ver;
1225 char *buf;
1226 int buflen;
1228 buf=xmalloc(10);buflen=10;
1229 if (!_wine_read_line(F,&buf,&buflen)) {
1230 free(buf);
1231 return 0;
1233 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1234 free(buf);
1235 return 0;
1237 if (ver!=REGISTRY_SAVE_VERSION) {
1238 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1239 free(buf);
1240 return 0;
1242 if (!_wine_read_line(F,&buf,&buflen)) {
1243 free(buf);
1244 return 0;
1246 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1247 free(buf);
1248 return 0;
1250 free(buf);
1251 return 1;
1255 /******************************************************************************
1256 * _wine_loadreg [Internal]
1258 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1260 FILE *F;
1262 TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1264 F = fopen(fn,"rb");
1265 if (F==NULL) {
1266 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1267 return;
1269 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1270 fclose(F);
1271 unlink(fn);
1272 return;
1274 fclose(F);
1277 /******************************************************************************
1278 * _flush_registry [Internal]
1280 * This function allow to flush section of the internal registry. It is mainly
1281 * implements to fix a problem with the global HKU and the local HKU.
1282 * Those two files are read to build the HKU\.Default branch to finaly copy
1283 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1284 * all the global HKU are saved onto the user's personal version of HKU hive.
1285 * which is bad...
1288 /* Forward declaration of recusive agent */
1289 static void _flush_reg(LPKEYSTRUCT from);
1291 static void _flush_registry( LPKEYSTRUCT from )
1293 /* make sure we have something... */
1294 if (from == NULL)
1295 return;
1297 /* Launch the recusive agent on sub branches */
1298 _flush_reg( from->nextsub );
1299 _flush_reg( from->next );
1301 /* Initialize pointers */
1302 from->nextsub = NULL;
1303 from->next = NULL;
1305 static void _flush_reg( LPKEYSTRUCT from )
1307 int j;
1309 /* make sure we have something... */
1310 if (from == NULL)
1311 return;
1314 * do the same for the child keys
1316 if (from->nextsub != NULL)
1317 _flush_reg(from->nextsub);
1320 * do the same for the sibling keys
1322 if (from->next != NULL)
1323 _flush_reg(from->next);
1326 * iterate through this key's values and delete them
1328 for (j=0;j<from->nrofvalues;j++)
1330 free( (from->values+j)->name);
1331 free( (from->values+j)->data);
1335 * free the structure
1337 if ( from != NULL )
1338 free(from);
1342 /******************************************************************************
1343 * _copy_registry [Internal]
1345 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1347 LPKEYSTRUCT lpxkey;
1348 int j;
1349 LPKEYVALUE valfrom;
1351 from=from->nextsub;
1352 while (from) {
1353 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1355 for (j=0;j<from->nrofvalues;j++) {
1356 LPWSTR name;
1357 LPBYTE data;
1359 valfrom = from->values+j;
1360 name=valfrom->name;
1361 if (name) name=strdupW(name);
1362 data=(LPBYTE)xmalloc(valfrom->len);
1363 memcpy(data,valfrom->data,valfrom->len);
1365 _find_or_add_value(
1366 lpxkey,
1367 name,
1368 valfrom->type,
1369 data,
1370 valfrom->len,
1371 valfrom->lastmodified
1374 _copy_registry(from,lpxkey);
1375 from = from->next;
1380 /* WINDOWS 95 REGISTRY LOADER */
1382 * Structure of a win95 registry database.
1383 * main header:
1384 * 0 : "CREG" - magic
1385 * 4 : DWORD version
1386 * 8 : DWORD offset_of_RGDB_part
1387 * 0C..0F: ? (someone fill in please)
1388 * 10: WORD number of RGDB blocks
1389 * 12: WORD ?
1390 * 14: WORD always 0000?
1391 * 16: WORD always 0001?
1392 * 18..1F: ? (someone fill in please)
1394 * 20: RGKN_section:
1395 * header:
1396 * 0 : "RGKN" - magic
1397 * 4 : DWORD offset to first RGDB section
1398 * 8 : DWORD offset to the root record
1399 * C..0x1B: ? (fill in)
1400 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1402 * Disk Key Entry Structure:
1403 * 00: DWORD - Free entry indicator(?)
1404 * 04: DWORD - Hash = sum of bytes of keyname
1405 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1406 * 0C: DWORD - disk address of PreviousLevel Key.
1407 * 10: DWORD - disk address of Next Sublevel Key.
1408 * 14: DWORD - disk address of Next Key (on same level).
1409 * DKEP>18: WORD - Nr, Low Significant part.
1410 * 1A: WORD - Nr, High Significant part.
1412 * The disk address always points to the nr part of the previous key entry
1413 * of the referenced key. Don't ask me why, or even if I got this correct
1414 * from staring at 1kg of hexdumps. (DKEP)
1416 * The High significant part of the structure seems to equal the number
1417 * of the RGDB section. The low significant part is a unique ID within
1418 * that RGDB section
1420 * There are two minor corrections to the position of that structure.
1421 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1422 * the DKE reread from there.
1423 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1424 * CPS - I have not experienced the above phenomenon in my registry files
1426 * RGDB_section:
1427 * 00: "RGDB" - magic
1428 * 04: DWORD offset to next RGDB section
1429 * 08: DWORD ?
1430 * 0C: WORD always 000d?
1431 * 0E: WORD RGDB block number
1432 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1433 * 14..1F: ?
1434 * 20.....: disk keys
1436 * disk key:
1437 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1438 * 08: WORD nrLS - low significant part of NR
1439 * 0A: WORD nrHS - high significant part of NR
1440 * 0C: DWORD bytesused - bytes used in this structure.
1441 * 10: WORD name_len - length of name in bytes. without \0
1442 * 12: WORD nr_of_values - number of values.
1443 * 14: char name[name_len] - name string. No \0.
1444 * 14+name_len: disk values
1445 * nextkeyoffset: ... next disk key
1447 * disk value:
1448 * 00: DWORD type - value type (hmm, could be WORD too)
1449 * 04: DWORD - unknown, usually 0
1450 * 08: WORD namelen - length of Name. 0 means name=NULL
1451 * 0C: WORD datalen - length of Data.
1452 * 10: char name[namelen] - name, no \0
1453 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1454 * 10+namelen+datalen: next values or disk key
1456 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1457 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1458 * structure) and reading another RGDB_section.
1459 * repeat until end of file.
1461 * An interesting relationship exists in RGDB_section. The value at offset
1462 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1463 * idea at the moment what this means. (Kevin Cozens)
1465 * FIXME: this description needs some serious help, yes.
1468 struct _w95keyvalue {
1469 unsigned long type;
1470 unsigned short datalen;
1471 char *name;
1472 unsigned char *data;
1473 unsigned long x1;
1474 int lastmodified;
1477 struct _w95key {
1478 char *name;
1479 int nrofvals;
1480 struct _w95keyvalue *values;
1481 struct _w95key *prevlvl;
1482 struct _w95key *nextsub;
1483 struct _w95key *next;
1487 struct _w95_info {
1488 char *rgknbuffer;
1489 int rgknsize;
1490 char *rgdbbuffer;
1491 int rgdbsize;
1492 int depth;
1493 int lastmodified;
1497 /******************************************************************************
1498 * _w95_processKey [Internal]
1500 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1501 int nrLS, int nrMS, struct _w95_info *info )
1504 /* Disk Key Header structure (RGDB part) */
1505 struct dkh {
1506 unsigned long nextkeyoff;
1507 unsigned short nrLS;
1508 unsigned short nrMS;
1509 unsigned long bytesused;
1510 unsigned short keynamelen;
1511 unsigned short values;
1512 unsigned long xx1;
1513 /* keyname */
1514 /* disk key values or nothing */
1516 /* Disk Key Value structure */
1517 struct dkv {
1518 unsigned long type;
1519 unsigned long x1;
1520 unsigned short valnamelen;
1521 unsigned short valdatalen;
1522 /* valname, valdata */
1526 struct dkh dkh;
1527 int bytesread = 0;
1528 char *rgdbdata = info->rgdbbuffer;
1529 int nbytes = info->rgdbsize;
1530 char *curdata = rgdbdata;
1531 char *end = rgdbdata + nbytes;
1532 int off_next_rgdb;
1533 char *next = rgdbdata;
1534 int nrgdb, i;
1535 LPKEYSTRUCT lpxkey;
1537 do {
1538 curdata = next;
1539 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1541 memcpy(&off_next_rgdb,curdata+4,4);
1542 next = curdata + off_next_rgdb;
1543 nrgdb = (int) *((short *)curdata + 7);
1545 } while (nrgdb != nrMS && (next < end));
1547 /* curdata now points to the start of the right RGDB section */
1548 curdata += 0x20;
1550 #define XREAD(whereto,len) \
1551 if ((curdata + len) <= end) {\
1552 memcpy(whereto,curdata,len);\
1553 curdata+=len;\
1554 bytesread+=len;\
1557 while (curdata < next) {
1558 struct dkh *xdkh = (struct dkh*)curdata;
1560 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1561 if (xdkh->nrLS == nrLS) {
1562 memcpy(&dkh,xdkh,sizeof(dkh));
1563 curdata += sizeof(dkh);
1564 break;
1566 curdata += xdkh->nextkeyoff;
1569 if (dkh.nrLS != nrLS) return (NULL);
1571 if (nrgdb != dkh.nrMS)
1572 return (NULL);
1574 assert((dkh.keynamelen<2) || curdata[0]);
1575 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1576 curdata += dkh.keynamelen;
1578 for (i=0;i< dkh.values; i++) {
1579 struct dkv dkv;
1580 LPBYTE data;
1581 int len;
1582 LPWSTR name;
1584 XREAD(&dkv,sizeof(dkv));
1586 name = strcvtA2W(curdata, dkv.valnamelen);
1587 curdata += dkv.valnamelen;
1589 if ((1 << dkv.type) & UNICONVMASK) {
1590 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1591 len = 2*(dkv.valdatalen + 1);
1592 } else {
1593 /* I don't think we want to NULL terminate all data */
1594 data = xmalloc(dkv.valdatalen);
1595 memcpy (data, curdata, dkv.valdatalen);
1596 len = dkv.valdatalen;
1599 curdata += dkv.valdatalen;
1601 _find_or_add_value(
1602 lpxkey,
1603 name,
1604 dkv.type,
1605 data,
1606 len,
1607 info->lastmodified
1610 return (lpxkey);
1613 /******************************************************************************
1614 * _w95_walkrgkn [Internal]
1616 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1617 struct _w95_info *info )
1620 /* Disk Key Entry structure (RGKN part) */
1621 struct dke {
1622 unsigned long x1;
1623 unsigned long x2;
1624 unsigned long x3;/*usually 0xFFFFFFFF */
1625 unsigned long prevlvl;
1626 unsigned long nextsub;
1627 unsigned long next;
1628 unsigned short nrLS;
1629 unsigned short nrMS;
1630 } *dke = (struct dke *)off;
1631 LPKEYSTRUCT lpxkey;
1633 if (dke == NULL) {
1634 dke = (struct dke *) ((char *)info->rgknbuffer);
1637 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1638 /* XXX <-- This is a hack*/
1639 if (!lpxkey) {
1640 lpxkey = prevkey;
1643 if (dke->nextsub != -1 &&
1644 ((dke->nextsub - 0x20) < info->rgknsize)
1645 && (dke->nextsub > 0x20)) {
1647 _w95_walkrgkn(lpxkey,
1648 info->rgknbuffer + dke->nextsub - 0x20,
1649 info);
1652 if (dke->next != -1 &&
1653 ((dke->next - 0x20) < info->rgknsize) &&
1654 (dke->next > 0x20)) {
1655 _w95_walkrgkn(prevkey,
1656 info->rgknbuffer + dke->next - 0x20,
1657 info);
1660 return;
1664 /******************************************************************************
1665 * _w95_loadreg [Internal]
1667 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1669 HFILE hfd;
1670 char magic[5];
1671 unsigned long where,version,rgdbsection,end;
1672 struct _w95_info info;
1673 OFSTRUCT ofs;
1674 BY_HANDLE_FILE_INFORMATION hfdinfo;
1676 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1677 hfd=OpenFile(fn,&ofs,OF_READ);
1678 if (hfd==HFILE_ERROR)
1679 return;
1680 magic[4]=0;
1681 if (4!=_lread(hfd,magic,4))
1682 return;
1683 if (strcmp(magic,"CREG")) {
1684 WARN_(reg)("%s is not a w95 registry.\n",fn);
1685 return;
1687 if (4!=_lread(hfd,&version,4))
1688 return;
1689 if (4!=_lread(hfd,&rgdbsection,4))
1690 return;
1691 if (-1==_llseek(hfd,0x20,SEEK_SET))
1692 return;
1693 if (4!=_lread(hfd,magic,4))
1694 return;
1695 if (strcmp(magic,"RGKN")) {
1696 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1697 return;
1700 /* STEP 1: Keylink structures */
1701 if (-1==_llseek(hfd,0x40,SEEK_SET))
1702 return;
1703 where = 0x40;
1704 end = rgdbsection;
1706 info.rgknsize = end - where;
1707 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1708 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1709 return;
1711 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1712 return;
1714 end = hfdinfo.nFileSizeLow;
1715 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1717 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1718 return;
1720 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1721 info.rgdbsize = end - rgdbsection;
1723 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1724 return;
1725 _lclose(hfd);
1727 _w95_walkrgkn(lpkey, NULL, &info);
1729 free (info.rgdbbuffer);
1730 free (info.rgknbuffer);
1734 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1737 reghack - windows 3.11 registry data format demo program.
1739 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1740 a combined hash table and tree description, and finally a text table.
1742 The header is obvious from the struct header. The taboff1 and taboff2
1743 fields are always 0x20, and their usage is unknown.
1745 The 8-byte entry table has various entry types.
1747 tabent[0] is a root index. The second word has the index of the root of
1748 the directory.
1749 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1750 the index of the key/value that has that hash. Data with the same
1751 hash value are on a circular list. The other three words in the
1752 hash entry are always zero.
1753 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1754 entry: dirent and keyent/valent. They are identified by context.
1755 tabent[freeidx] is the first free entry. The first word in a free entry
1756 is the index of the next free entry. The last has 0 as a link.
1757 The other three words in the free list are probably irrelevant.
1759 Entries in text table are preceeded by a word at offset-2. This word
1760 has the value (2*index)+1, where index is the referring keyent/valent
1761 entry in the table. I have no suggestion for the 2* and the +1.
1762 Following the word, there are N bytes of data, as per the keyent/valent
1763 entry length. The offset of the keyent/valent entry is from the start
1764 of the text table to the first data byte.
1766 This information is not available from Microsoft. The data format is
1767 deduced from the reg.dat file by me. Mistakes may
1768 have been made. I claim no rights and give no guarantees for this program.
1770 Tor Sjøwall, tor@sn.no
1773 /* reg.dat header format */
1774 struct _w31_header {
1775 char cookie[8]; /* 'SHCC3.10' */
1776 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1777 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1778 unsigned long tabcnt; /* number of entries in index table */
1779 unsigned long textoff; /* offset of text part */
1780 unsigned long textsize; /* byte size of text part */
1781 unsigned short hashsize; /* hash size */
1782 unsigned short freeidx; /* free index */
1785 /* generic format of table entries */
1786 struct _w31_tabent {
1787 unsigned short w0, w1, w2, w3;
1790 /* directory tabent: */
1791 struct _w31_dirent {
1792 unsigned short sibling_idx; /* table index of sibling dirent */
1793 unsigned short child_idx; /* table index of child dirent */
1794 unsigned short key_idx; /* table index of key keyent */
1795 unsigned short value_idx; /* table index of value valent */
1798 /* key tabent: */
1799 struct _w31_keyent {
1800 unsigned short hash_idx; /* hash chain index for string */
1801 unsigned short refcnt; /* reference count */
1802 unsigned short length; /* length of string */
1803 unsigned short string_off; /* offset of string in text table */
1806 /* value tabent: */
1807 struct _w31_valent {
1808 unsigned short hash_idx; /* hash chain index for string */
1809 unsigned short refcnt; /* reference count */
1810 unsigned short length; /* length of string */
1811 unsigned short string_off; /* offset of string in text table */
1814 /* recursive helper function to display a directory tree */
1815 void
1816 __w31_dumptree( unsigned short idx,
1817 unsigned char *txt,
1818 struct _w31_tabent *tab,
1819 struct _w31_header *head,
1820 LPKEYSTRUCT lpkey,
1821 time_t lastmodified,
1822 int level
1824 struct _w31_dirent *dir;
1825 struct _w31_keyent *key;
1826 struct _w31_valent *val;
1827 LPKEYSTRUCT xlpkey = NULL;
1828 LPWSTR name,value;
1829 static char tail[400];
1831 while (idx!=0) {
1832 dir=(struct _w31_dirent*)&tab[idx];
1834 if (dir->key_idx) {
1835 key = (struct _w31_keyent*)&tab[dir->key_idx];
1837 memcpy(tail,&txt[key->string_off],key->length);
1838 tail[key->length]='\0';
1839 /* all toplevel entries AND the entries in the
1840 * toplevel subdirectory belong to \SOFTWARE\Classes
1842 if (!level && !lstrcmpA(tail,".classes")) {
1843 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1844 idx=dir->sibling_idx;
1845 continue;
1847 name=strdupA2W(tail);
1849 xlpkey=_find_or_add_key(lpkey,name);
1851 /* only add if leaf node or valued node */
1852 if (dir->value_idx!=0||dir->child_idx==0) {
1853 if (dir->value_idx) {
1854 val=(struct _w31_valent*)&tab[dir->value_idx];
1855 memcpy(tail,&txt[val->string_off],val->length);
1856 tail[val->length]='\0';
1857 value=strdupA2W(tail);
1858 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1861 } else {
1862 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1864 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1865 idx=dir->sibling_idx;
1870 /******************************************************************************
1871 * _w31_loadreg [Internal]
1873 void _w31_loadreg(void) {
1874 HFILE hf;
1875 struct _w31_header head;
1876 struct _w31_tabent *tab;
1877 unsigned char *txt;
1878 int len;
1879 OFSTRUCT ofs;
1880 BY_HANDLE_FILE_INFORMATION hfinfo;
1881 time_t lastmodified;
1882 LPKEYSTRUCT lpkey;
1884 TRACE_(reg)("(void)\n");
1886 hf = OpenFile("reg.dat",&ofs,OF_READ);
1887 if (hf==HFILE_ERROR)
1888 return;
1890 /* read & dump header */
1891 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1892 ERR_(reg)("reg.dat is too short.\n");
1893 _lclose(hf);
1894 return;
1896 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1897 ERR_(reg)("reg.dat has bad signature.\n");
1898 _lclose(hf);
1899 return;
1902 len = head.tabcnt * sizeof(struct _w31_tabent);
1903 /* read and dump index table */
1904 tab = xmalloc(len);
1905 if (len!=_lread(hf,tab,len)) {
1906 ERR_(reg)("couldn't read %d bytes.\n",len);
1907 free(tab);
1908 _lclose(hf);
1909 return;
1912 /* read text */
1913 txt = xmalloc(head.textsize);
1914 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1915 ERR_(reg)("couldn't seek to textblock.\n");
1916 free(tab);
1917 free(txt);
1918 _lclose(hf);
1919 return;
1921 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1922 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1923 free(tab);
1924 free(txt);
1925 _lclose(hf);
1926 return;
1929 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1930 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1931 free(tab);
1932 free(txt);
1933 _lclose(hf);
1934 return;
1936 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1937 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1938 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1939 free(tab);
1940 free(txt);
1941 _lclose(hf);
1942 return;
1946 /**********************************************************************************
1947 * SHELL_LoadRegistry [Internal]
1949 void SHELL_LoadRegistry( void )
1951 char *fn, *home;
1952 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1953 HKEY hkey;
1955 TRACE_(reg)("(void)\n");
1957 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1958 HKU = lookup_hkey(HKEY_USERS);
1959 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1961 /* Load windows 3.1 entries */
1962 _w31_loadreg();
1963 /* Load windows 95 entries */
1964 _w95_loadreg("C:\\system.1st", HKLM);
1965 _w95_loadreg("system.dat", HKLM);
1966 _w95_loadreg("user.dat", HKU);
1969 * Load the global HKU hive directly from sysconfdir
1971 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1974 * Load the global machine defaults directly form sysconfdir
1976 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1979 * Load the user saved registries
1981 if ((home = getenv( "HOME" )))
1984 * Load user's personal versions of global HKU/.Default keys
1986 fn=(char*)xmalloc(
1987 strlen(home)+
1988 strlen(WINE_PREFIX)+
1989 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1991 strcpy(fn, home);
1992 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1993 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1994 free(fn);
1997 * Load HKCU, attempt to get the registry location from the config
1998 * file first, if exist, load and keep going.
2000 fn = xmalloc( MAX_PATHNAME_LEN );
2001 if ( PROFILE_GetWineIniString(
2002 "Registry",
2003 "UserFileName",
2004 "",
2005 fn,
2006 MAX_PATHNAME_LEN - 1))
2008 _wine_loadreg(HKCU,fn,0);
2010 free (fn);
2012 fn=(char*)xmalloc(
2013 strlen(home)+
2014 strlen(WINE_PREFIX)+
2015 strlen(SAVE_CURRENT_USER)+2);
2017 strcpy(fn, home);
2018 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
2019 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
2020 free(fn);
2023 * Load HKLM, attempt to get the registry location from the config
2024 * file first, if exist, load and keep going.
2026 fn = xmalloc ( MAX_PATHNAME_LEN);
2027 if ( PROFILE_GetWineIniString(
2028 "Registry",
2029 "LocalMachineFileName",
2030 "",
2031 fn,
2032 MAX_PATHNAME_LEN - 1))
2034 _wine_loadreg(HKLM, fn, 0);
2036 free(fn);
2038 fn=(char*)xmalloc(
2039 strlen(home)+
2040 strlen(WINE_PREFIX)+
2041 strlen(SAVE_LOCAL_MACHINE)+2);
2043 strcpy(fn,home);
2044 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2045 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2046 free(fn);
2048 else
2050 WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
2054 * Obtain the handle of the HKU\.Default key.
2055 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2057 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2058 lpkey = lookup_hkey(hkey);
2059 if(!lpkey)
2060 WARN_(reg)("Could not create global user default key\n");
2061 else
2062 _copy_registry(lpkey, HKCU );
2064 RegCloseKey(hkey);
2067 * Since HKU is built from the global HKU and the local user HKU file we must
2068 * flush the HKU tree we have built at this point otherwise the part brought
2069 * in from the global HKU is saved into the local HKU. To avoid this
2070 * useless dupplication of HKU keys we reread the local HKU key.
2073 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2074 _flush_registry(HKU);
2076 /* Reload user's local HKU hive */
2077 if (home)
2079 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
2080 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
2082 strcpy(fn,home);
2083 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2085 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2087 free(fn);
2091 * Make sure the update mode is there
2093 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2095 DWORD junk,type,len;
2096 char data[5];
2098 len=4;
2099 if (( RegQueryValueExA(
2100 hkey,
2101 VAL_SAVEUPDATED,
2102 &junk,
2103 &type,
2104 data,
2105 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2107 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2110 RegCloseKey(hkey);
2115 /********************* API FUNCTIONS ***************************************/
2117 * Open Keys.
2119 * All functions are stubs to RegOpenKeyEx32W where all the
2120 * magic happens.
2122 * Callpath:
2123 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2124 * RegOpenKey32W -> RegOpenKeyEx32W
2128 /******************************************************************************
2129 * RegOpenKeyEx32W [ADVAPI32.150]
2130 * Opens the specified key
2132 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2134 * PARAMS
2135 * hkey [I] Handle of open key
2136 * lpszSubKey [I] Name of subkey to open
2137 * dwReserved [I] Reserved - must be zero
2138 * samDesired [I] Security access mask
2139 * retkey [O] Address of handle of open key
2141 * RETURNS
2142 * Success: ERROR_SUCCESS
2143 * Failure: Error code
2145 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2146 REGSAM samDesired, LPHKEY retkey )
2148 LPKEYSTRUCT lpNextKey,lpxkey;
2149 LPWSTR *wps;
2150 int wpc,i;
2152 TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2153 samDesired,retkey);
2155 lpNextKey = lookup_hkey( hkey );
2156 if (!lpNextKey)
2157 return ERROR_INVALID_HANDLE;
2159 if (!lpszSubKey || !*lpszSubKey) {
2160 /* Either NULL or pointer to empty string, so return a new handle
2161 to the original hkey */
2162 currenthandle += 2;
2163 add_handle(currenthandle,lpNextKey,samDesired);
2164 *retkey=currenthandle;
2165 return ERROR_SUCCESS;
2168 if (lpszSubKey[0] == '\\') {
2169 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2170 return ERROR_BAD_PATHNAME;
2173 split_keypath(lpszSubKey,&wps,&wpc);
2174 i = 0;
2175 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2176 lpxkey = lpNextKey;
2178 while (wps[i]) {
2179 lpxkey=lpNextKey->nextsub;
2180 while (lpxkey) {
2181 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2182 break;
2184 lpxkey=lpxkey->next;
2187 if (!lpxkey) {
2188 TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2189 FREE_KEY_PATH;
2190 return ERROR_FILE_NOT_FOUND;
2192 i++;
2193 lpNextKey = lpxkey;
2196 currenthandle += 2;
2197 add_handle(currenthandle,lpxkey,samDesired);
2198 *retkey = currenthandle;
2199 TRACE_(reg)(" Returning %x\n", currenthandle);
2200 FREE_KEY_PATH;
2201 return ERROR_SUCCESS;
2205 /******************************************************************************
2206 * RegOpenKeyEx32A [ADVAPI32.149]
2208 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2209 REGSAM samDesired, LPHKEY retkey )
2211 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2212 DWORD ret;
2214 TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2215 samDesired,retkey);
2216 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2217 free(lpszSubKeyW);
2218 return ret;
2222 /******************************************************************************
2223 * RegOpenKey32W [ADVAPI32.151]
2225 * PARAMS
2226 * hkey [I] Handle of open key
2227 * lpszSubKey [I] Address of name of subkey to open
2228 * retkey [O] Address of handle of open key
2230 * RETURNS
2231 * Success: ERROR_SUCCESS
2232 * Failure: Error code
2234 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2236 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2237 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2241 /******************************************************************************
2242 * RegOpenKey32A [ADVAPI32.148]
2244 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2246 DWORD ret;
2247 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2248 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2249 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2250 free(lpszSubKeyW);
2251 return ret;
2255 /******************************************************************************
2256 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2258 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2260 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2261 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2266 * Create keys
2268 * All those functions convert their respective
2269 * arguments and call RegCreateKeyExW at the end.
2271 * We stay away from the Ex functions as long as possible because there are
2272 * differences in the return values
2274 * Callpath:
2275 * RegCreateKeyEx32A \
2276 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2280 /******************************************************************************
2281 * RegCreateKeyEx32W [ADVAPI32.131]
2283 * PARAMS
2284 * hkey [I] Handle of an open key
2285 * lpszSubKey [I] Address of subkey name
2286 * dwReserved [I] Reserved - must be 0
2287 * lpszClass [I] Address of class string
2288 * fdwOptions [I] Special options flag
2289 * samDesired [I] Desired security access
2290 * lpSecAttribs [I] Address of key security structure
2291 * retkey [O] Address of buffer for opened handle
2292 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2294 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2295 DWORD dwReserved, LPWSTR lpszClass,
2296 DWORD fdwOptions, REGSAM samDesired,
2297 LPSECURITY_ATTRIBUTES lpSecAttribs,
2298 LPHKEY retkey, LPDWORD lpDispos )
2300 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2301 LPWSTR *wps;
2302 int wpc,i;
2304 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2305 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2306 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2308 lpNextKey = lookup_hkey(hkey);
2309 if (!lpNextKey)
2310 return ERROR_INVALID_HANDLE;
2312 /* Check for valid options */
2313 switch(fdwOptions) {
2314 case REG_OPTION_NON_VOLATILE:
2315 case REG_OPTION_VOLATILE:
2316 case REG_OPTION_BACKUP_RESTORE:
2317 break;
2318 default:
2319 return ERROR_INVALID_PARAMETER;
2322 /* Sam has to be a combination of the following */
2323 if (!(samDesired &
2324 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2325 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2326 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2327 return ERROR_INVALID_PARAMETER;
2329 if (!lpszSubKey || !*lpszSubKey) {
2330 currenthandle += 2;
2331 add_handle(currenthandle,lpNextKey,samDesired);
2332 *retkey=currenthandle;
2333 TRACE_(reg)("Returning %x\n", currenthandle);
2334 lpNextKey->flags|=REG_OPTION_TAINTED;
2335 return ERROR_SUCCESS;
2338 if (lpszSubKey[0] == '\\') {
2339 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2340 return ERROR_BAD_PATHNAME;
2343 split_keypath(lpszSubKey,&wps,&wpc);
2344 i = 0;
2345 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2346 lpxkey = lpNextKey;
2347 while (wps[i]) {
2348 lpxkey=lpNextKey->nextsub;
2349 while (lpxkey) {
2350 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2351 break;
2352 lpxkey=lpxkey->next;
2354 if (!lpxkey)
2355 break;
2356 i++;
2357 lpNextKey = lpxkey;
2359 if (lpxkey) {
2360 currenthandle += 2;
2361 add_handle(currenthandle,lpxkey,samDesired);
2362 lpxkey->flags |= REG_OPTION_TAINTED;
2363 *retkey = currenthandle;
2364 TRACE_(reg)("Returning %x\n", currenthandle);
2365 if (lpDispos)
2366 *lpDispos = REG_OPENED_EXISTING_KEY;
2367 FREE_KEY_PATH;
2368 return ERROR_SUCCESS;
2371 /* Good. Now the hard part */
2372 while (wps[i]) {
2373 lplpPrevKey = &(lpNextKey->nextsub);
2374 lpxkey = *lplpPrevKey;
2375 while (lpxkey) {
2376 lplpPrevKey = &(lpxkey->next);
2377 lpxkey = *lplpPrevKey;
2379 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2380 if (!*lplpPrevKey) {
2381 FREE_KEY_PATH;
2382 TRACE_(reg)("Returning OUTOFMEMORY\n");
2383 return ERROR_OUTOFMEMORY;
2385 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2386 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2387 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2388 (*lplpPrevKey)->next = NULL;
2389 (*lplpPrevKey)->nextsub = NULL;
2390 (*lplpPrevKey)->values = NULL;
2391 (*lplpPrevKey)->nrofvalues = 0;
2392 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2393 if (lpszClass)
2394 (*lplpPrevKey)->class = strdupW(lpszClass);
2395 else
2396 (*lplpPrevKey)->class = NULL;
2397 lpNextKey = *lplpPrevKey;
2398 i++;
2400 currenthandle += 2;
2401 add_handle(currenthandle,lpNextKey,samDesired);
2403 /*FIXME: flag handling correct? */
2404 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2405 if (lpszClass)
2406 lpNextKey->class = strdupW(lpszClass);
2407 else
2408 lpNextKey->class = NULL;
2409 *retkey = currenthandle;
2410 TRACE_(reg)("Returning %x\n", currenthandle);
2411 if (lpDispos)
2412 *lpDispos = REG_CREATED_NEW_KEY;
2413 FREE_KEY_PATH;
2414 return ERROR_SUCCESS;
2418 /******************************************************************************
2419 * RegCreateKeyEx32A [ADVAPI32.130]
2421 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2422 LPSTR lpszClass, DWORD fdwOptions,
2423 REGSAM samDesired,
2424 LPSECURITY_ATTRIBUTES lpSecAttribs,
2425 LPHKEY retkey, LPDWORD lpDispos )
2427 LPWSTR lpszSubKeyW, lpszClassW;
2428 DWORD ret;
2430 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2431 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2432 retkey,lpDispos);
2434 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2435 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2437 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2438 fdwOptions, samDesired, lpSecAttribs, retkey,
2439 lpDispos );
2441 if(lpszSubKeyW) free(lpszSubKeyW);
2442 if(lpszClassW) free(lpszClassW);
2444 return ret;
2448 /******************************************************************************
2449 * RegCreateKey32W [ADVAPI32.132]
2451 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2453 DWORD junk;
2454 LPKEYSTRUCT lpNextKey;
2456 TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2458 /* This check is here because the return value is different than the
2459 one from the Ex functions */
2460 lpNextKey = lookup_hkey(hkey);
2461 if (!lpNextKey)
2462 return ERROR_BADKEY;
2464 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2465 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2466 retkey, &junk);
2470 /******************************************************************************
2471 * RegCreateKey32A [ADVAPI32.129]
2473 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2475 DWORD ret;
2476 LPWSTR lpszSubKeyW;
2478 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2479 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2480 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2481 if(lpszSubKeyW) free(lpszSubKeyW);
2482 return ret;
2486 /******************************************************************************
2487 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2489 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2491 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2492 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2497 * Query Value Functions
2498 * Win32 differs between keynames and valuenames.
2499 * multiple values may belong to one key, the special value
2500 * with name NULL is the default value used by the win31
2501 * compat functions.
2503 * Callpath:
2504 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2505 * RegQueryValue32W -> RegQueryValueEx32W
2509 /******************************************************************************
2510 * RegQueryValueEx32W [ADVAPI32.158]
2511 * Retrieves type and data for a specified name associated with an open key
2513 * PARAMS
2514 * hkey [I] Handle of key to query
2515 * lpValueName [I] Name of value to query
2516 * lpdwReserved [I] Reserved - must be NULL
2517 * lpdwType [O] Address of buffer for value type. If NULL, the type
2518 * is not required.
2519 * lpbData [O] Address of data buffer. If NULL, the actual data is
2520 * not required.
2521 * lpcbData [I/O] Address of data buffer size
2523 * RETURNS
2524 * ERROR_SUCCESS: Success
2525 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2526 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2528 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR lpValueName,
2529 LPDWORD lpdwReserved, LPDWORD lpdwType,
2530 LPBYTE lpbData, LPDWORD lpcbData )
2532 LPKEYSTRUCT lpkey;
2533 int i;
2534 DWORD ret;
2536 TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2537 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2539 lpkey = lookup_hkey(hkey);
2541 if (!lpkey)
2542 return ERROR_INVALID_HANDLE;
2544 if ((lpbData && ! lpcbData) || lpdwReserved)
2545 return ERROR_INVALID_PARAMETER;
2547 /* An empty name string is equivalent to NULL */
2548 if (lpValueName && !*lpValueName)
2549 lpValueName = NULL;
2551 if (lpValueName==NULL)
2552 { /* Use key's unnamed or default value, if any */
2553 for (i=0;i<lpkey->nrofvalues;i++)
2554 if (lpkey->values[i].name==NULL)
2555 break;
2557 else
2558 { /* Search for the key name */
2559 for (i=0;i<lpkey->nrofvalues;i++)
2560 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2561 break;
2564 if (i==lpkey->nrofvalues)
2565 { TRACE_(reg)(" Key not found\n");
2566 if (lpValueName==NULL)
2567 { /* Empty keyname not found */
2568 if (lpbData)
2569 { *(WCHAR*)lpbData = 0;
2570 *lpcbData = 2;
2572 if (lpdwType)
2573 *lpdwType = REG_SZ;
2574 TRACE_(reg)(" Returning an empty string\n");
2575 return ERROR_SUCCESS;
2577 return ERROR_FILE_NOT_FOUND;
2580 ret = ERROR_SUCCESS;
2582 if (lpdwType) /* type required ?*/
2583 *lpdwType = lpkey->values[i].type;
2585 if (lpbData) /* data required ?*/
2586 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2587 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2588 else {
2589 *lpcbData = lpkey->values[i].len;
2590 ret = ERROR_MORE_DATA;
2594 if (lpcbData) /* size required ?*/
2595 { *lpcbData = lpkey->values[i].len;
2598 debug_print_value ( lpbData, &lpkey->values[i]);
2600 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2602 return ret;
2606 /******************************************************************************
2607 * RegQueryValue32W [ADVAPI32.159]
2609 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2610 LPLONG lpcbData )
2612 HKEY xhkey;
2613 DWORD ret,lpdwType;
2615 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2616 lpcbData?*lpcbData:0);
2618 /* Only open subkey, if we really do descend */
2619 if (lpszSubKey && *lpszSubKey) {
2620 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2621 if (ret != ERROR_SUCCESS) {
2622 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2623 return ret;
2625 } else
2626 xhkey = hkey;
2628 lpdwType = REG_SZ;
2629 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2630 lpcbData );
2631 if (xhkey != hkey)
2632 RegCloseKey(xhkey);
2633 return ret;
2637 /******************************************************************************
2638 * RegQueryValueEx32A [ADVAPI32.157]
2640 * NOTES:
2641 * the documantation is wrong: if the buffer is to small it remains untouched
2643 * FIXME: check returnvalue (len) for an empty key
2645 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR lpszValueName,
2646 LPDWORD lpdwReserved, LPDWORD lpdwType,
2647 LPBYTE lpbData, LPDWORD lpcbData )
2649 LPWSTR lpszValueNameW;
2650 LPBYTE mybuf = NULL;
2651 DWORD ret, mytype, mylen = 0;
2653 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2654 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2656 if (!lpcbData && lpbData) /* buffer without size is illegal */
2657 { return ERROR_INVALID_PARAMETER;
2660 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2662 /* get just the type first */
2663 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2665 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2666 { if(lpszValueNameW) free(lpszValueNameW);
2667 return ret;
2670 if (lpcbData) /* at least length requested? */
2671 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2672 { if (lpbData ) /* value requested? */
2673 { mylen = 2*( *lpcbData );
2674 mybuf = (LPBYTE)xmalloc( mylen );
2677 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2679 if (ret == ERROR_SUCCESS )
2680 { if ( lpbData )
2681 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2685 *lpcbData = mylen/2; /* size is in byte! */
2687 else /* no strings, call it straight */
2688 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2692 if (lpdwType) /* type when requested */
2693 { *lpdwType = mytype;
2696 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2698 if(mybuf) free(mybuf);
2699 if(lpszValueNameW) free(lpszValueNameW);
2700 return ret;
2704 /******************************************************************************
2705 * RegQueryValueEx16 [KERNEL.225]
2707 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2708 LPDWORD lpdwReserved, LPDWORD lpdwType,
2709 LPBYTE lpbData, LPDWORD lpcbData )
2711 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2712 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2713 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2714 lpbData, lpcbData );
2718 /******************************************************************************
2719 * RegQueryValue32A [ADVAPI32.156]
2721 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2722 LPLONG lpcbData )
2724 HKEY xhkey;
2725 DWORD ret, dwType;
2727 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2728 lpcbData?*lpcbData:0);
2730 if (lpszSubKey && *lpszSubKey) {
2731 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2732 if( ret != ERROR_SUCCESS )
2733 return ret;
2734 } else
2735 xhkey = hkey;
2737 dwType = REG_SZ;
2738 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2739 lpcbData );
2740 if( xhkey != hkey )
2741 RegCloseKey( xhkey );
2742 return ret;
2746 /******************************************************************************
2747 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2749 * NOTES
2750 * Is this HACK still applicable?
2752 * HACK
2753 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2754 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2755 * Aldus FH4)
2757 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2758 LPDWORD lpcbData )
2760 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2761 lpcbData?*lpcbData:0);
2763 if (lpcbData)
2764 *lpcbData &= 0xFFFF;
2765 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2770 * Setting values of Registry keys
2772 * Callpath:
2773 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2774 * RegSetValue32W -> RegSetValueEx32W
2778 /******************************************************************************
2779 * RegSetValueEx32W [ADVAPI32.170]
2780 * Sets the data and type of a value under a register key
2782 * PARAMS
2783 * hkey [I] Handle of key to set value for
2784 * lpszValueName [I] Name of value to set
2785 * dwReserved [I] Reserved - must be zero
2786 * dwType [I] Flag for value type
2787 * lpbData [I] Address of value data
2788 * cbData [I] Size of value data
2790 * RETURNS
2791 * Success: ERROR_SUCCESS
2792 * Failure: Error code
2794 * NOTES
2795 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2797 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR lpszValueName,
2798 DWORD dwReserved, DWORD dwType,
2799 CONST BYTE *lpbData, DWORD cbData)
2801 LPKEYSTRUCT lpkey;
2802 int i;
2804 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2805 dwReserved, dwType, lpbData, cbData);
2807 lpkey = lookup_hkey( hkey );
2809 if (!lpkey)
2810 return ERROR_INVALID_HANDLE;
2812 lpkey->flags |= REG_OPTION_TAINTED;
2814 if (lpszValueName==NULL) {
2815 /* Sets type and name for key's unnamed or default value */
2816 for (i=0;i<lpkey->nrofvalues;i++)
2817 if (lpkey->values[i].name==NULL)
2818 break;
2819 } else {
2820 for (i=0;i<lpkey->nrofvalues;i++)
2821 if ( lpkey->values[i].name &&
2822 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2824 break;
2826 if (i==lpkey->nrofvalues) {
2827 lpkey->values = (LPKEYVALUE)xrealloc(
2828 lpkey->values,
2829 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2831 lpkey->nrofvalues++;
2832 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2834 if (lpkey->values[i].name==NULL) {
2835 if (lpszValueName)
2836 lpkey->values[i].name = strdupW(lpszValueName);
2837 else
2838 lpkey->values[i].name = NULL;
2841 if (dwType == REG_SZ)
2842 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2844 lpkey->values[i].len = cbData;
2845 lpkey->values[i].type = dwType;
2846 if (lpkey->values[i].data !=NULL)
2847 free(lpkey->values[i].data);
2848 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2849 lpkey->values[i].lastmodified = time(NULL);
2850 memcpy(lpkey->values[i].data,lpbData,cbData);
2851 return ERROR_SUCCESS;
2855 /******************************************************************************
2856 * RegSetValueEx32A [ADVAPI32.169]
2858 * NOTES
2859 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2861 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR lpszValueName,
2862 DWORD dwReserved, DWORD dwType,
2863 CONST BYTE *lpbData, DWORD cbData )
2865 LPBYTE buf;
2866 LPWSTR lpszValueNameW;
2867 DWORD ret;
2869 if (!lpbData)
2870 return (ERROR_INVALID_PARAMETER);
2872 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2873 dwReserved,dwType,lpbData,cbData);
2875 if ((1<<dwType) & UNICONVMASK)
2876 { if (dwType == REG_SZ)
2877 cbData = strlen ((LPCSTR)lpbData)+1;
2879 buf = (LPBYTE)xmalloc( cbData *2 );
2880 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2881 cbData=2*cbData;
2883 else
2884 buf=(LPBYTE)lpbData;
2886 if (lpszValueName)
2887 lpszValueNameW = strdupA2W(lpszValueName);
2888 else
2889 lpszValueNameW = NULL;
2891 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2893 if (lpszValueNameW)
2894 free(lpszValueNameW);
2896 if (buf!=lpbData)
2897 free(buf);
2899 return ret;
2903 /******************************************************************************
2904 * RegSetValueEx16 [KERNEL.226]
2906 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2907 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2909 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2910 dwReserved,dwType,lpbData,cbData);
2911 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2912 cbData );
2916 /******************************************************************************
2917 * RegSetValue32W [ADVAPI32.171]
2919 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2920 LPCWSTR lpszData, DWORD cbData )
2922 HKEY xhkey;
2923 DWORD ret;
2925 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2926 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2928 if (lpszSubKey && *lpszSubKey) {
2929 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2930 if (ret!=ERROR_SUCCESS)
2931 return ret;
2932 } else
2933 xhkey=hkey;
2934 if (dwType!=REG_SZ) {
2935 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2936 dwType=REG_SZ;
2938 if (cbData!=2*lstrlenW(lpszData)+2) {
2939 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2940 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2942 cbData=2*lstrlenW(lpszData)+2;
2944 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2945 if (hkey!=xhkey)
2946 RegCloseKey(xhkey);
2947 return ret;
2951 /******************************************************************************
2952 * RegSetValue32A [ADVAPI32.168]
2955 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2956 LPCSTR lpszData, DWORD cbData )
2958 DWORD ret;
2959 HKEY xhkey;
2961 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2962 if (lpszSubKey && *lpszSubKey) {
2963 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2964 if (ret!=ERROR_SUCCESS)
2965 return ret;
2966 } else
2967 xhkey=hkey;
2969 if (dwType!=REG_SZ) {
2970 TRACE_(reg)("dwType=%ld!\n",dwType);
2971 dwType=REG_SZ;
2973 if (cbData!=strlen(lpszData)+1)
2974 cbData=strlen(lpszData)+1;
2975 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2976 if (xhkey!=hkey)
2977 RegCloseKey(xhkey);
2978 return ret;
2982 /******************************************************************************
2983 * RegSetValue16 [KERNEL.221] [SHELL.5]
2985 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2986 LPCSTR lpszData, DWORD cbData )
2988 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2989 debugstr_a(lpszData),cbData);
2990 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2995 * Key Enumeration
2997 * Callpath:
2998 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2999 * RegEnumKey32W -> RegEnumKeyEx32W
3003 /******************************************************************************
3004 * RegEnumKeyEx32W [ADVAPI32.139]
3006 * PARAMS
3007 * hkey [I] Handle to key to enumerate
3008 * iSubKey [I] Index of subkey to enumerate
3009 * lpszName [O] Buffer for subkey name
3010 * lpcchName [O] Size of subkey buffer
3011 * lpdwReserved [I] Reserved
3012 * lpszClass [O] Buffer for class string
3013 * lpcchClass [O] Size of class buffer
3014 * ft [O] Time key last written to
3016 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3017 LPDWORD lpcchName, LPDWORD lpdwReserved,
3018 LPWSTR lpszClass, LPDWORD lpcchClass,
3019 FILETIME *ft )
3021 LPKEYSTRUCT lpkey,lpxkey;
3023 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
3024 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
3026 lpkey = lookup_hkey( hkey );
3027 if (!lpkey)
3028 return ERROR_INVALID_HANDLE;
3030 if (!lpkey->nextsub)
3031 return ERROR_NO_MORE_ITEMS;
3032 lpxkey=lpkey->nextsub;
3034 /* Traverse the subkeys */
3035 while (iSubkey && lpxkey) {
3036 iSubkey--;
3037 lpxkey=lpxkey->next;
3040 if (iSubkey || !lpxkey)
3041 return ERROR_NO_MORE_ITEMS;
3042 if (lstrlenW(lpxkey->keyname)+1>*lpcchName) {
3043 *lpcchName = lstrlenW(lpxkey->keyname)+1;
3044 return ERROR_MORE_DATA;
3046 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3048 if (*lpcchName)
3049 *lpcchName = lstrlenW(lpszName);
3051 if (lpszClass) {
3052 /* FIXME: what should we write into it? */
3053 *lpszClass = 0;
3054 *lpcchClass = 2;
3056 return ERROR_SUCCESS;
3060 /******************************************************************************
3061 * RegEnumKey32W [ADVAPI32.140]
3063 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3064 DWORD lpcchName )
3066 FILETIME ft;
3068 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3069 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3073 /******************************************************************************
3074 * RegEnumKeyEx32A [ADVAPI32.138]
3076 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3077 LPDWORD lpcchName, LPDWORD lpdwReserved,
3078 LPSTR lpszClass, LPDWORD lpcchClass,
3079 FILETIME *ft )
3081 DWORD ret,lpcchNameW,lpcchClassW;
3082 LPWSTR lpszNameW,lpszClassW;
3085 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3086 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3088 if (lpszName) {
3089 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3090 lpcchNameW = *lpcchName;
3091 } else {
3092 lpszNameW = NULL;
3093 lpcchNameW = 0;
3095 if (lpszClass) {
3096 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3097 lpcchClassW = *lpcchClass;
3098 } else {
3099 lpszClassW =0;
3100 lpcchClassW=0;
3102 ret=RegEnumKeyExW(
3103 hkey,
3104 iSubkey,
3105 lpszNameW,
3106 &lpcchNameW,
3107 lpdwReserved,
3108 lpszClassW,
3109 &lpcchClassW,
3112 if (ret==ERROR_SUCCESS) {
3113 lstrcpyWtoA(lpszName,lpszNameW);
3114 *lpcchName=strlen(lpszName);
3115 if (lpszClassW) {
3116 lstrcpyWtoA(lpszClass,lpszClassW);
3117 *lpcchClass=strlen(lpszClass);
3120 if (lpszNameW)
3121 free(lpszNameW);
3122 if (lpszClassW)
3123 free(lpszClassW);
3124 return ret;
3128 /******************************************************************************
3129 * RegEnumKey32A [ADVAPI32.137]
3131 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3132 DWORD lpcchName )
3134 FILETIME ft;
3136 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3137 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3138 NULL, &ft );
3142 /******************************************************************************
3143 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3145 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3146 DWORD lpcchName )
3148 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3149 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3154 * Enumerate Registry Values
3156 * Callpath:
3157 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3161 /******************************************************************************
3162 * RegEnumValue32W [ADVAPI32.142]
3164 * PARAMS
3165 * hkey [I] Handle to key to query
3166 * iValue [I] Index of value to query
3167 * lpszValue [O] Value string
3168 * lpcchValue [I/O] Size of value buffer (in wchars)
3169 * lpdReserved [I] Reserved
3170 * lpdwType [O] Type code
3171 * lpbData [O] Value data
3172 * lpcbData [I/O] Size of data buffer (in bytes)
3174 * Note: wide character functions that take and/or return "character counts"
3175 * use TCHAR (that is unsigned short or char) not byte counts.
3177 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3178 LPDWORD lpcchValue, LPDWORD lpdReserved,
3179 LPDWORD lpdwType, LPBYTE lpbData,
3180 LPDWORD lpcbData )
3182 LPKEYSTRUCT lpkey;
3183 LPKEYVALUE val;
3185 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3186 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3188 lpkey = lookup_hkey( hkey );
3190 if (!lpcbData && lpbData)
3191 return ERROR_INVALID_PARAMETER;
3193 if (!lpkey)
3194 return ERROR_INVALID_HANDLE;
3196 if (lpkey->nrofvalues <= iValue)
3197 return ERROR_NO_MORE_ITEMS;
3199 val = &(lpkey->values[iValue]);
3201 if (val->name) {
3202 if (lstrlenW(val->name)+1>*lpcchValue) {
3203 *lpcchValue = lstrlenW(val->name)+1;
3204 return ERROR_MORE_DATA;
3206 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3207 *lpcchValue=lstrlenW(val->name);
3208 } else {
3209 *lpszValue = 0;
3210 *lpcchValue = 0;
3213 /* Can be NULL if the type code is not required */
3214 if (lpdwType)
3215 *lpdwType = val->type;
3217 if (lpbData) {
3218 if (val->len>*lpcbData) {
3219 *lpcbData = val->len;
3220 return ERROR_MORE_DATA;
3222 memcpy(lpbData,val->data,val->len);
3223 *lpcbData = val->len;
3226 debug_print_value ( val->data, val );
3227 return ERROR_SUCCESS;
3231 /******************************************************************************
3232 * RegEnumValue32A [ADVAPI32.141]
3234 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3235 LPDWORD lpcchValue, LPDWORD lpdReserved,
3236 LPDWORD lpdwType, LPBYTE lpbData,
3237 LPDWORD lpcbData )
3239 LPWSTR lpszValueW;
3240 LPBYTE lpbDataW;
3241 DWORD ret,lpcbDataW;
3242 DWORD dwType;
3244 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3245 lpdReserved,lpdwType,lpbData,lpcbData);
3247 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3248 if (lpbData) {
3249 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3250 lpcbDataW = *lpcbData;
3251 } else
3252 lpbDataW = NULL;
3254 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3255 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3257 if (lpdwType)
3258 *lpdwType = dwType;
3260 if (ret==ERROR_SUCCESS) {
3261 lstrcpyWtoA(lpszValue,lpszValueW);
3262 if (lpbData) {
3263 if ((1<<dwType) & UNICONVMASK) {
3264 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3265 } else {
3266 if (lpcbDataW > *lpcbData) {
3267 *lpcbData = lpcbDataW;
3268 ret = ERROR_MORE_DATA;
3269 } else
3270 memcpy(lpbData,lpbDataW,lpcbDataW);
3272 *lpcbData = lpcbDataW;
3275 if (lpbDataW) free(lpbDataW);
3276 if (lpszValueW) free(lpszValueW);
3277 return ret;
3281 /******************************************************************************
3282 * RegEnumValue16 [KERNEL.223]
3284 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3285 LPDWORD lpcchValue, LPDWORD lpdReserved,
3286 LPDWORD lpdwType, LPBYTE lpbData,
3287 LPDWORD lpcbData )
3289 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3290 lpdReserved,lpdwType,lpbData,lpcbData);
3291 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3292 lpdwType, lpbData, lpcbData );
3296 /******************************************************************************
3297 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3298 * Releases the handle of the specified key
3300 * PARAMS
3301 * hkey [I] Handle of key to close
3303 * RETURNS
3304 * Success: ERROR_SUCCESS
3305 * Failure: Error code
3307 DWORD WINAPI RegCloseKey( HKEY hkey )
3309 TRACE_(reg)("(%x)\n",hkey);
3311 /* The standard handles are allowed to succeed, even though they are not
3312 closed */
3313 if (is_standard_hkey(hkey))
3314 return ERROR_SUCCESS;
3316 return remove_handle(hkey);
3321 * Delete registry key
3323 * Callpath:
3324 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3328 /******************************************************************************
3329 * RegDeleteKey32W [ADVAPI32.134]
3331 * PARAMS
3332 * hkey [I] Handle to open key
3333 * lpszSubKey [I] Name of subkey to delete
3335 * RETURNS
3336 * Success: ERROR_SUCCESS
3337 * Failure: Error code
3339 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3341 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3342 LPWSTR *wps;
3343 int wpc,i;
3345 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3347 lpNextKey = lookup_hkey(hkey);
3348 if (!lpNextKey)
3349 return ERROR_INVALID_HANDLE;
3351 /* Subkey param cannot be NULL */
3352 if (!lpszSubKey || !*lpszSubKey)
3353 return ERROR_BADKEY;
3355 /* We need to know the previous key in the hier. */
3356 split_keypath(lpszSubKey,&wps,&wpc);
3357 i = 0;
3358 lpxkey = lpNextKey;
3359 while (i<wpc-1) {
3360 lpxkey=lpNextKey->nextsub;
3361 while (lpxkey) {
3362 TRACE_(reg)(" Scanning [%s]\n",
3363 debugstr_w(lpxkey->keyname));
3364 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3365 break;
3366 lpxkey=lpxkey->next;
3368 if (!lpxkey) {
3369 FREE_KEY_PATH;
3370 TRACE_(reg)(" Not found.\n");
3371 /* not found is success */
3372 return ERROR_SUCCESS;
3374 i++;
3375 lpNextKey = lpxkey;
3377 lpxkey = lpNextKey->nextsub;
3378 lplpPrevKey = &(lpNextKey->nextsub);
3379 while (lpxkey) {
3380 TRACE_(reg)(" Scanning [%s]\n",
3381 debugstr_w(lpxkey->keyname));
3382 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3383 break;
3384 lplpPrevKey = &(lpxkey->next);
3385 lpxkey = lpxkey->next;
3388 if (!lpxkey) {
3389 FREE_KEY_PATH;
3390 WARN_(reg)(" Not found.\n");
3391 return ERROR_FILE_NOT_FOUND;
3394 if (lpxkey->nextsub) {
3395 FREE_KEY_PATH;
3396 WARN_(reg)(" Not empty.\n");
3397 return ERROR_CANTWRITE;
3399 *lplpPrevKey = lpxkey->next;
3400 free(lpxkey->keyname);
3401 if (lpxkey->class)
3402 free(lpxkey->class);
3403 if (lpxkey->values)
3404 free(lpxkey->values);
3405 free(lpxkey);
3406 FREE_KEY_PATH;
3407 TRACE_(reg)(" Done.\n");
3408 return ERROR_SUCCESS;
3412 /******************************************************************************
3413 * RegDeleteKey32A [ADVAPI32.133]
3415 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3417 LPWSTR lpszSubKeyW;
3418 DWORD ret;
3420 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3421 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3422 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3423 if(lpszSubKeyW) free(lpszSubKeyW);
3424 return ret;
3428 /******************************************************************************
3429 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3431 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3433 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3434 return RegDeleteKeyA( hkey, lpszSubKey );
3439 * Delete registry value
3441 * Callpath:
3442 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3446 /******************************************************************************
3447 * RegDeleteValue32W [ADVAPI32.136]
3449 * PARAMS
3450 * hkey [I]
3451 * lpszValue [I]
3453 * RETURNS
3455 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3457 DWORD i;
3458 LPKEYSTRUCT lpkey;
3459 LPKEYVALUE val;
3461 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3463 lpkey = lookup_hkey( hkey );
3464 if (!lpkey)
3465 return ERROR_INVALID_HANDLE;
3467 if (lpszValue) {
3468 for (i=0;i<lpkey->nrofvalues;i++)
3469 if ( lpkey->values[i].name &&
3470 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3472 break;
3473 } else {
3474 for (i=0;i<lpkey->nrofvalues;i++)
3475 if (lpkey->values[i].name==NULL)
3476 break;
3479 if (i == lpkey->nrofvalues)
3480 return ERROR_FILE_NOT_FOUND;
3482 val = lpkey->values+i;
3483 if (val->name) free(val->name);
3484 if (val->data) free(val->data);
3485 memcpy(
3486 lpkey->values+i,
3487 lpkey->values+i+1,
3488 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3490 lpkey->values = (LPKEYVALUE)xrealloc(
3491 lpkey->values,
3492 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3494 lpkey->nrofvalues--;
3495 return ERROR_SUCCESS;
3499 /******************************************************************************
3500 * RegDeleteValue32A [ADVAPI32.135]
3502 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3504 LPWSTR lpszValueW;
3505 DWORD ret;
3507 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3508 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3509 ret = RegDeleteValueW( hkey, lpszValueW );
3510 if(lpszValueW) free(lpszValueW);
3511 return ret;
3515 /******************************************************************************
3516 * RegDeleteValue16 [KERNEL.222]
3518 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3520 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3521 return RegDeleteValueA( hkey, lpszValue );
3525 /******************************************************************************
3526 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3527 * Immediately writes key to registry.
3528 * Only returns after data has been written to disk.
3530 * FIXME: does it really wait until data is written ?
3532 * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3533 * written if this function really works (and only if !).
3535 * PARAMS
3536 * hkey [I] Handle of key to write
3538 * RETURNS
3539 * Success: ERROR_SUCCESS
3540 * Failure: Error code
3542 DWORD WINAPI RegFlushKey( HKEY hkey )
3544 LPKEYSTRUCT lpkey;
3546 TRACE_(reg)("(%x)\n", hkey);
3548 lpkey = lookup_hkey( hkey );
3549 if (!lpkey)
3550 return ERROR_BADKEY;
3552 SHELL_SaveRegistryBranch(find_root_key(lpkey), TRUE);
3553 return ERROR_SUCCESS;
3557 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3560 /******************************************************************************
3561 * RegQueryInfoKey32W [ADVAPI32.153]
3563 * PARAMS
3564 * hkey [I] Handle to key to query
3565 * lpszClass [O] Buffer for class string
3566 * lpcchClass [O] Size of class string buffer
3567 * lpdwReserved [I] Reserved
3568 * lpcSubKeys [I] Buffer for number of subkeys
3569 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3570 * lpcchMaxClass [O] Buffer for longest class string length
3571 * lpcValues [O] Buffer for number of value entries
3572 * lpcchMaxValueName [O] Buffer for longest value name length
3573 * lpccbMaxValueData [O] Buffer for longest value data length
3574 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3575 * ft
3576 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3577 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3578 * lpcchClass is NULL
3579 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3580 * (it's hard to test validity, so test !NULL instead)
3582 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3583 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3584 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3585 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3586 LPDWORD lpcchMaxValueName,
3587 LPDWORD lpccbMaxValueData,
3588 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3590 LPKEYSTRUCT lpkey,lpxkey;
3591 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3592 int i;
3594 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3595 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3596 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3597 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3599 lpkey = lookup_hkey(hkey);
3600 if (!lpkey)
3601 return ERROR_INVALID_HANDLE;
3602 if (lpszClass) {
3603 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3604 return ERROR_INVALID_PARAMETER;
3606 /* either lpcchClass is valid or this is win95 and lpcchClass
3607 could be invalid */
3608 if (lpkey->class) {
3609 DWORD classLen = lstrlenW(lpkey->class);
3611 if (lpcchClass && classLen+1>*lpcchClass) {
3612 *lpcchClass=classLen+1;
3613 return ERROR_MORE_DATA;
3615 if (lpcchClass)
3616 *lpcchClass=classLen;
3617 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3618 } else {
3619 *lpszClass = 0;
3620 if (lpcchClass)
3621 *lpcchClass = 0;
3623 } else {
3624 if (lpcchClass)
3625 *lpcchClass = lstrlenW(lpkey->class);
3627 lpxkey=lpkey->nextsub;
3628 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3629 while (lpxkey) {
3630 nrofkeys++;
3631 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3632 maxsubkey=lstrlenW(lpxkey->keyname);
3633 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3634 maxclass=lstrlenW(lpxkey->class);
3635 lpxkey=lpxkey->next;
3637 for (i=0;i<lpkey->nrofvalues;i++) {
3638 LPKEYVALUE val=lpkey->values+i;
3640 if (val->name && lstrlenW(val->name)>maxvname)
3641 maxvname=lstrlenW(val->name);
3642 if (val->len>maxvdata)
3643 maxvdata=val->len;
3645 if (!maxclass) maxclass = 1;
3646 if (!maxvname) maxvname = 1;
3647 if (lpcValues)
3648 *lpcValues = lpkey->nrofvalues;
3649 if (lpcSubKeys)
3650 *lpcSubKeys = nrofkeys;
3651 if (lpcchMaxSubkey)
3652 *lpcchMaxSubkey = maxsubkey;
3653 if (lpcchMaxClass)
3654 *lpcchMaxClass = maxclass;
3655 if (lpcchMaxValueName)
3656 *lpcchMaxValueName= maxvname;
3657 if (lpccbMaxValueData)
3658 *lpccbMaxValueData= maxvdata;
3659 return ERROR_SUCCESS;
3663 /******************************************************************************
3664 * RegQueryInfoKey32A [ADVAPI32.152]
3666 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3667 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3668 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3669 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3670 LPDWORD lpccbMaxValueData,
3671 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3673 LPWSTR lpszClassW = NULL;
3674 DWORD ret;
3676 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3677 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3678 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3679 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3681 if (lpszClass) {
3682 if (lpcchClass) {
3683 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3684 } else if (VERSION_GetVersion() == WIN95) {
3685 /* win95 allows lpcchClass to be null */
3686 /* we don't know how big lpszClass is, would
3687 MAX_PATHNAME_LEN be the correct default? */
3688 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3691 } else
3692 lpszClassW = NULL;
3693 ret=RegQueryInfoKeyW(
3694 hkey,
3695 lpszClassW,
3696 lpcchClass,
3697 lpdwReserved,
3698 lpcSubKeys,
3699 lpcchMaxSubkey,
3700 lpcchMaxClass,
3701 lpcValues,
3702 lpcchMaxValueName,
3703 lpccbMaxValueData,
3704 lpcbSecurityDescriptor,
3707 if (ret==ERROR_SUCCESS && lpszClass)
3708 lstrcpyWtoA(lpszClass,lpszClassW);
3709 if (lpszClassW)
3710 free(lpszClassW);
3711 return ret;
3715 /******************************************************************************
3716 * RegConnectRegistry32W [ADVAPI32.128]
3718 * PARAMS
3719 * lpMachineName [I] Address of name of remote computer
3720 * hHey [I] Predefined registry handle
3721 * phkResult [I] Address of buffer for remote registry handle
3723 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3724 LPHKEY phkResult )
3726 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3728 if (!lpMachineName || !*lpMachineName) {
3729 /* Use the local machine name */
3730 return RegOpenKey16( hKey, "", phkResult );
3733 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3734 return ERROR_BAD_NETPATH;
3738 /******************************************************************************
3739 * RegConnectRegistry32A [ADVAPI32.127]
3741 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3743 DWORD ret;
3744 LPWSTR machineW = strdupA2W(machine);
3745 ret = RegConnectRegistryW( machineW, hkey, reskey );
3746 free(machineW);
3747 return ret;
3751 /******************************************************************************
3752 * RegGetKeySecurity [ADVAPI32.144]
3753 * Retrieves a copy of security descriptor protecting the registry key
3755 * PARAMS
3756 * hkey [I] Open handle of key to set
3757 * SecurityInformation [I] Descriptor contents
3758 * pSecurityDescriptor [O] Address of descriptor for key
3759 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3761 * RETURNS
3762 * Success: ERROR_SUCCESS
3763 * Failure: Error code
3765 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3766 SECURITY_INFORMATION SecurityInformation,
3767 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3768 LPDWORD lpcbSecurityDescriptor )
3770 LPKEYSTRUCT lpkey;
3772 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3773 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3775 lpkey = lookup_hkey( hkey );
3776 if (!lpkey)
3777 return ERROR_INVALID_HANDLE;
3779 /* FIXME: Check for valid SecurityInformation values */
3781 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3782 return ERROR_INSUFFICIENT_BUFFER;
3784 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3785 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3787 return ERROR_SUCCESS;
3791 /******************************************************************************
3792 * RegLoadKey32W [ADVAPI32.???]
3794 * PARAMS
3795 * hkey [I] Handle of open key
3796 * lpszSubKey [I] Address of name of subkey
3797 * lpszFile [I] Address of filename for registry information
3799 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3801 LPKEYSTRUCT lpkey;
3802 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3804 /* Do this check before the hkey check */
3805 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3806 return ERROR_INVALID_PARAMETER;
3808 lpkey = lookup_hkey( hkey );
3809 if (!lpkey)
3810 return ERROR_INVALID_HANDLE;
3812 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3813 debugstr_w(lpszFile));
3815 return ERROR_SUCCESS;
3819 /******************************************************************************
3820 * RegLoadKey32A [ADVAPI32.???]
3822 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3824 LONG ret;
3825 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3826 LPWSTR lpszFileW = strdupA2W(lpszFile);
3827 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3828 if(lpszFileW) free(lpszFileW);
3829 if(lpszSubKeyW) free(lpszSubKeyW);
3830 return ret;
3834 /******************************************************************************
3835 * RegNotifyChangeKeyValue [ADVAPI32.???]
3837 * PARAMS
3838 * hkey [I] Handle of key to watch
3839 * fWatchSubTree [I] Flag for subkey notification
3840 * fdwNotifyFilter [I] Changes to be reported
3841 * hEvent [I] Handle of signaled event
3842 * fAsync [I] Flag for asynchronous reporting
3844 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3845 DWORD fdwNotifyFilter, HANDLE hEvent,
3846 BOOL fAsync )
3848 LPKEYSTRUCT lpkey;
3849 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3850 hEvent,fAsync);
3852 lpkey = lookup_hkey( hkey );
3853 if (!lpkey)
3854 return ERROR_INVALID_HANDLE;
3856 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3857 hEvent,fAsync);
3859 return ERROR_SUCCESS;
3863 /******************************************************************************
3864 * RegUnLoadKey32W [ADVAPI32.173]
3866 * PARAMS
3867 * hkey [I] Handle of open key
3868 * lpSubKey [I] Address of name of subkey to unload
3870 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3872 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3873 return ERROR_SUCCESS;
3877 /******************************************************************************
3878 * RegUnLoadKey32A [ADVAPI32.172]
3880 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3882 LONG ret;
3883 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3884 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3885 if(lpSubKeyW) free(lpSubKeyW);
3886 return ret;
3890 /******************************************************************************
3891 * RegSetKeySecurity [ADVAPI32.167]
3893 * PARAMS
3894 * hkey [I] Open handle of key to set
3895 * SecurityInfo [I] Descriptor contents
3896 * pSecurityDesc [I] Address of descriptor for key
3898 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3899 PSECURITY_DESCRIPTOR pSecurityDesc )
3901 LPKEYSTRUCT lpkey;
3903 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3905 /* It seems to perform this check before the hkey check */
3906 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3907 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3908 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3909 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3910 /* Param OK */
3911 } else
3912 return ERROR_INVALID_PARAMETER;
3914 if (!pSecurityDesc)
3915 return ERROR_INVALID_PARAMETER;
3917 lpkey = lookup_hkey( hkey );
3918 if (!lpkey)
3919 return ERROR_INVALID_HANDLE;
3921 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3923 return ERROR_SUCCESS;
3927 /******************************************************************************
3928 * RegSaveKey32W [ADVAPI32.166]
3930 * PARAMS
3931 * hkey [I] Handle of key where save begins
3932 * lpFile [I] Address of filename to save to
3933 * sa [I] Address of security structure
3935 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3936 LPSECURITY_ATTRIBUTES sa )
3938 LPKEYSTRUCT lpkey;
3940 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3942 /* It appears to do this check before the hkey check */
3943 if (!lpFile || !*lpFile)
3944 return ERROR_INVALID_PARAMETER;
3946 lpkey = lookup_hkey( hkey );
3947 if (!lpkey)
3948 return ERROR_INVALID_HANDLE;
3950 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3952 return ERROR_SUCCESS;
3956 /******************************************************************************
3957 * RegSaveKey32A [ADVAPI32.165]
3959 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3960 LPSECURITY_ATTRIBUTES sa )
3962 LONG ret;
3963 LPWSTR lpFileW = strdupA2W(lpFile);
3964 ret = RegSaveKeyW( hkey, lpFileW, sa );
3965 free(lpFileW);
3966 return ret;
3970 /******************************************************************************
3971 * RegRestoreKey32W [ADVAPI32.164]
3973 * PARAMS
3974 * hkey [I] Handle of key where restore begins
3975 * lpFile [I] Address of filename containing saved tree
3976 * dwFlags [I] Optional flags
3978 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3980 LPKEYSTRUCT lpkey;
3982 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3984 /* It seems to do this check before the hkey check */
3985 if (!lpFile || !*lpFile)
3986 return ERROR_INVALID_PARAMETER;
3988 lpkey = lookup_hkey( hkey );
3989 if (!lpkey)
3990 return ERROR_INVALID_HANDLE;
3992 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3994 /* Check for file existence */
3996 return ERROR_SUCCESS;
4000 /******************************************************************************
4001 * RegRestoreKey32A [ADVAPI32.163]
4003 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
4005 LONG ret;
4006 LPWSTR lpFileW = strdupA2W(lpFile);
4007 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
4008 if(lpFileW) free(lpFileW);
4009 return ret;
4013 /******************************************************************************
4014 * RegReplaceKey32W [ADVAPI32.162]
4016 * PARAMS
4017 * hkey [I] Handle of open key
4018 * lpSubKey [I] Address of name of subkey
4019 * lpNewFile [I] Address of filename for file with new data
4020 * lpOldFile [I] Address of filename for backup file
4022 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
4023 LPCWSTR lpOldFile )
4025 LPKEYSTRUCT lpkey;
4027 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
4028 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4030 lpkey = lookup_hkey( hkey );
4031 if (!lpkey)
4032 return ERROR_INVALID_HANDLE;
4034 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
4035 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4037 return ERROR_SUCCESS;
4041 /******************************************************************************
4042 * RegReplaceKey32A [ADVAPI32.161]
4044 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
4045 LPCSTR lpOldFile )
4047 LONG ret;
4048 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4049 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4050 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4051 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
4052 free(lpOldFileW);
4053 free(lpNewFileW);
4054 free(lpSubKeyW);
4055 return ret;