Several bug fixes in save_key().
[wine/multimedia.git] / misc / registry.c
bloba04246af9960ca0e5abf5fb64b0122a452e42e6f
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 "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #ifdef HAVE_SYS_ERRNO_H
30 #include <sys/errno.h>
31 #endif
32 #include <sys/types.h>
33 #include <sys/fcntl.h>
34 #include <sys/stat.h>
35 #include <assert.h>
36 #include <time.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wine/winbase16.h"
40 #include "wine/winestring.h"
41 #include "winerror.h"
42 #include "file.h"
43 #include "heap.h"
44 #include "debugtools.h"
45 #include "xmalloc.h"
46 #include "options.h"
47 #include "winreg.h"
48 #include "winversion.h"
49 #include "server.h"
50 #include "services.h"
52 DEFAULT_DEBUG_CHANNEL(reg)
54 static void REGISTRY_Init(void);
55 /* FIXME: following defines should be configured global ... */
57 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
58 #define WINE_PREFIX "/.wine"
59 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
60 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
62 /* relative in ~user/.wine/ : */
63 #define SAVE_CURRENT_USER "user.reg"
64 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
65 #define SAVE_LOCAL_MACHINE "system.reg"
67 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
68 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
71 /* what valuetypes do we need to convert? */
72 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
77 * QUESTION
78 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
79 * If so, can we remove them?
80 * ANSWER
81 * No, the memory handling functions are called very often in here,
82 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
83 * loading 100 times slower. -MM
85 static LPWSTR strdupA2W(LPCSTR src)
87 if(src) {
88 LPWSTR dest=xmalloc(2*strlen(src)+2);
89 lstrcpyAtoW(dest,src);
90 return dest;
92 return NULL;
95 LPWSTR strcvtA2W(LPCSTR src, int nchars)
98 LPWSTR dest = xmalloc (2 * nchars + 2);
100 lstrcpynAtoW(dest,src,nchars+1);
101 dest[nchars] = 0;
102 return dest;
107 /******************************************************************************
108 * REGISTRY_Init [Internal]
109 * Registry initialisation, allocates some default keys.
111 static void REGISTRY_Init(void) {
112 HKEY hkey;
113 char buf[200];
115 TRACE_(reg)("(void)\n");
117 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
118 RegCloseKey(hkey);
120 /* This was an Open, but since it is called before the real registries
121 are loaded, it was changed to a Create - MTB 980507*/
122 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
123 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
124 RegCloseKey(hkey);
126 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
127 * CurrentVersion
128 * CurrentBuildNumber
129 * CurrentType
130 * string RegisteredOwner
131 * string RegisteredOrganization
134 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
135 * string SysContact
136 * string SysLocation
137 * SysServices
139 if (-1!=gethostname(buf,200)) {
140 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
141 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
142 RegCloseKey(hkey);
147 /************************ SAVE Registry Function ****************************/
149 #define REGISTRY_SAVE_VERSION 0x00000001
151 /* Registry saveformat:
152 * If you change it, increase above number by 1, which will flush
153 * old registry database files.
155 * Global:
156 * "WINE REGISTRY Version %d"
157 * subkeys....
158 * Subkeys:
159 * keyname
160 * valuename=lastmodified,type,data
161 * ...
162 * subkeys
163 * ...
164 * keyname,valuename,stringdata:
165 * the usual ascii characters from 0x00-0xff (well, not 0x00)
166 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
167 * ( "=\\\t" escaped in \uXXXX form.)
168 * type,lastmodified:
169 * int
171 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
173 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
174 * SaveOnlyUpdatedKeys=yes
177 /* Same as RegSaveKey but with Unix pathnames */
178 static void save_key( HKEY hkey, const char *filename )
180 struct save_registry_request *req = get_req_buffer();
181 int count = 0;
182 DWORD ret;
183 HANDLE handle;
184 char *p;
185 char *name = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 20 );
187 if (!name) return;
188 strcpy( name, filename );
189 if ((p = strrchr( name, '/' ))) p++;
190 else p = name;
192 for (;;)
194 sprintf( p, "reg%04x.tmp", count++ );
195 handle = FILE_CreateFile( name, GENERIC_WRITE, 0, NULL,
196 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
197 if (handle != INVALID_HANDLE_VALUE) break;
198 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) break;
201 if (handle != INVALID_HANDLE_VALUE)
203 req->hkey = hkey;
204 req->file = handle;
205 ret = server_call_noerr( REQ_SAVE_REGISTRY );
206 CloseHandle( handle );
207 if (ret) unlink( name );
208 else if (rename( name, filename ) == -1)
210 ERR( "Failed to move %s to %s: ", name, filename );
211 perror( "rename" );
212 unlink( name );
215 HeapFree( GetProcessHeap(), 0, name );
219 /******************************************************************************
220 * SHELL_SaveRegistryBranch [Internal]
222 * Saves main registry branch specified by hkey.
224 static void SHELL_SaveRegistryBranch(HKEY hkey)
226 char *fn, *home;
228 /* Find out what to save to, get from config file */
229 BOOL writeToHome = PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
230 BOOL writeToAlt = PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
232 /* FIXME: does this check apply to all keys written below ? */
233 if (!(home = getenv( "HOME" )))
234 ERR_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
236 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
237 if (hkey == HKEY_CLASSES_ROOT) hkey = HKEY_LOCAL_MACHINE;
239 switch (hkey)
241 case HKEY_CURRENT_USER:
242 fn = xmalloc( MAX_PATHNAME_LEN );
243 if (writeToAlt && PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
244 fn, MAX_PATHNAME_LEN - 1))
245 save_key( HKEY_CURRENT_USER, fn );
246 free (fn);
248 if (home && writeToHome)
250 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
251 strlen(SAVE_CURRENT_USER) + 2 );
252 strcpy(fn,home);
253 strcat(fn,WINE_PREFIX);
255 /* create the directory. don't care about errorcodes. */
256 mkdir(fn,0755); /* drwxr-xr-x */
257 strcat(fn,"/"SAVE_CURRENT_USER);
258 save_key( HKEY_CURRENT_USER, fn );
259 free(fn);
261 break;
262 case HKEY_LOCAL_MACHINE:
263 /* Try first saving according to the defined location in .winerc */
264 fn = xmalloc ( MAX_PATHNAME_LEN);
265 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
266 fn, MAX_PATHNAME_LEN - 1))
267 save_key( HKEY_LOCAL_MACHINE, fn );
268 free (fn);
270 if (home && writeToHome)
272 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
273 strlen(SAVE_LOCAL_MACHINE) + 2);
274 strcpy(fn,home);
275 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
276 save_key( HKEY_LOCAL_MACHINE, fn );
277 free(fn);
279 break;
280 case HKEY_USERS:
281 fn = xmalloc( MAX_PATHNAME_LEN );
282 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
283 fn, MAX_PATHNAME_LEN - 1))
284 save_key( HKEY_USERS, fn );
285 free (fn);
287 if (home && writeToHome)
289 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
290 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
291 strcpy(fn,home);
292 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
293 save_key( HKEY_USERS, fn );
294 free(fn);
296 break;
297 default:
298 ERR_(reg)("unknown/invalid key handle !\n");
299 break;
304 /******************************************************************************
305 * SHELL_SaveRegistry [Internal]
307 void SHELL_SaveRegistry( void )
309 struct set_registry_levels_request *req = get_req_buffer();
310 char buf[4];
311 HKEY hkey;
312 int all;
314 TRACE_(reg)("(void)\n");
316 all=0;
317 if (RegOpenKeyA(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
319 strcpy(buf,"yes");
321 else
323 DWORD len,junk,type;
325 len=4;
326 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
327 VAL_SAVEUPDATED,
328 &junk,
329 &type,
330 buf,
331 &len)) || (type!=REG_SZ))
333 strcpy(buf,"yes");
335 RegCloseKey(hkey);
338 if (lstrcmpiA(buf,"yes")) all = 1;
340 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
341 req->current = 1;
342 req->saving = !all;
343 req->version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 0 ) ? 2 : 1;
344 server_call( REQ_SET_REGISTRY_LEVELS );
346 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER);
347 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE);
348 SHELL_SaveRegistryBranch(HKEY_USERS);
351 /* Periodic save callback */
352 static void CALLBACK periodic_save( ULONG_PTR dummy )
354 SHELL_SaveRegistry();
357 /************************ LOAD Registry Function ****************************/
361 /******************************************************************************
362 * _find_or_add_key [Internal]
364 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
366 HKEY subkey;
367 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
368 if (keyname) free( keyname );
369 return subkey;
372 /******************************************************************************
373 * _find_or_add_value [Internal]
375 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
377 RegSetValueExW( hkey, name, 0, type, data, len );
378 if (name) free( name );
379 if (data) free( data );
383 /******************************************************************************
384 * _wine_read_line [Internal]
386 * reads a line including dynamically enlarging the readbuffer and throwing
387 * away comments
389 static int _wine_read_line( FILE *F, char **buf, int *len )
391 char *s,*curread;
392 int mylen,curoff;
394 curread = *buf;
395 mylen = *len;
396 **buf = '\0';
397 while (1) {
398 while (1) {
399 s=fgets(curread,mylen,F);
400 if (s==NULL)
401 return 0; /* EOF */
402 if (NULL==(s=strchr(curread,'\n'))) {
403 /* buffer wasn't large enough */
404 curoff = strlen(*buf);
405 *buf = xrealloc(*buf,*len*2);
406 curread = *buf + curoff;
407 mylen = *len; /* we filled up the buffer and
408 * got new '*len' bytes to fill
410 *len = *len * 2;
411 } else {
412 *s='\0';
413 break;
416 /* throw away comments */
417 if (**buf=='#' || **buf==';') {
418 curread = *buf;
419 mylen = *len;
420 continue;
422 if (s) /* got end of line */
423 break;
425 return 1;
429 /******************************************************************************
430 * _wine_read_USTRING [Internal]
432 * converts a char* into a UNICODE string (up to a special char)
433 * and returns the position exactly after that string
435 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
437 char *s;
438 LPWSTR ws;
440 /* read up to "=" or "\0" or "\n" */
441 s = buf;
442 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
443 ws = *str;
444 while (*s && (*s!='\n') && (*s!='=')) {
445 if (*s!='\\')
446 *ws++=*((unsigned char*)s++);
447 else {
448 s++;
449 if (!*s) {
450 /* Dangling \ ... may only happen if a registry
451 * write was short. FIXME: What do to?
453 break;
455 if (*s=='\\') {
456 *ws++='\\';
457 s++;
458 continue;
460 if (*s!='u') {
461 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
462 *ws++='\\';
463 *ws++=*s++;
464 } else {
465 char xbuf[5];
466 int wc;
468 s++;
469 memcpy(xbuf,s,4);xbuf[4]='\0';
470 if (!sscanf(xbuf,"%x",&wc))
471 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
472 s+=4;
473 *ws++ =(unsigned short)wc;
477 *ws = 0;
478 return s;
482 /******************************************************************************
483 * _wine_loadsubkey [Internal]
485 * NOTES
486 * It seems like this is returning a boolean. Should it?
488 * RETURNS
489 * Success: 1
490 * Failure: 0
492 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
494 HKEY subkey;
495 int i;
496 char *s;
497 LPWSTR name;
499 TRACE_(reg)("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
501 /* Good. We already got a line here ... so parse it */
502 subkey = 0;
503 while (1) {
504 i=0;s=*buf;
505 while (*s=='\t') {
506 s++;
507 i++;
509 if (i>level) {
510 if (!subkey) {
511 WARN_(reg)("Got a subhierarchy without resp. key?\n");
512 return 0;
514 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
515 if (!_wine_read_line(F,buf,buflen))
516 goto done;
517 continue;
520 /* let the caller handle this line */
521 if (i<level || **buf=='\0')
522 goto done;
524 /* it can be: a value or a keyname. Parse the name first */
525 s=_wine_read_USTRING(s,&name);
527 /* switch() default: hack to avoid gotos */
528 switch (0) {
529 default:
530 if (*s=='\0') {
531 if (subkey) RegCloseKey( subkey );
532 subkey=_find_or_add_key(hkey,name);
533 } else {
534 LPBYTE data;
535 int len,lastmodified,type;
537 if (*s!='=') {
538 WARN_(reg)("Unexpected character: %c\n",*s);
539 break;
541 s++;
542 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
543 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
544 break;
546 /* skip the 2 , */
547 s=strchr(s,',');s++;
548 s=strchr(s,',');
549 if (!s++) {
550 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
551 break;
553 if (type == REG_SZ || type == REG_EXPAND_SZ) {
554 s=_wine_read_USTRING(s,(LPWSTR*)&data);
555 len = lstrlenW((LPWSTR)data)*2+2;
556 } else {
557 len=strlen(s)/2;
558 data = (LPBYTE)xmalloc(len+1);
559 for (i=0;i<len;i++) {
560 data[i]=0;
561 if (*s>='0' && *s<='9')
562 data[i]=(*s-'0')<<4;
563 if (*s>='a' && *s<='f')
564 data[i]=(*s-'a'+'\xa')<<4;
565 if (*s>='A' && *s<='F')
566 data[i]=(*s-'A'+'\xa')<<4;
567 s++;
568 if (*s>='0' && *s<='9')
569 data[i]|=*s-'0';
570 if (*s>='a' && *s<='f')
571 data[i]|=*s-'a'+'\xa';
572 if (*s>='A' && *s<='F')
573 data[i]|=*s-'A'+'\xa';
574 s++;
577 _find_or_add_value(hkey,name,type,data,len);
580 /* read the next line */
581 if (!_wine_read_line(F,buf,buflen))
582 goto done;
584 done:
585 if (subkey) RegCloseKey( subkey );
586 return 1;
590 /******************************************************************************
591 * _wine_loadsubreg [Internal]
593 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
595 int ver;
596 char *buf;
597 int buflen;
599 buf=xmalloc(10);buflen=10;
600 if (!_wine_read_line(F,&buf,&buflen)) {
601 free(buf);
602 return 0;
604 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
605 free(buf);
606 return 0;
608 if (ver!=REGISTRY_SAVE_VERSION) {
609 if (ver == 2) /* new version */
611 HANDLE file;
612 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
613 FILE_ATTRIBUTE_NORMAL, -1 )) != INVALID_HANDLE_VALUE)
615 struct load_registry_request *req = get_req_buffer();
616 req->hkey = hkey;
617 req->file = file;
618 req->name[0] = 0;
619 server_call( REQ_LOAD_REGISTRY );
620 CloseHandle( file );
622 free( buf );
623 return 1;
625 else
627 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
628 free(buf);
629 return 0;
632 if (!_wine_read_line(F,&buf,&buflen)) {
633 free(buf);
634 return 0;
636 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
637 free(buf);
638 return 0;
640 free(buf);
641 return 1;
645 /******************************************************************************
646 * _wine_loadreg [Internal]
648 static void _wine_loadreg( HKEY hkey, char *fn )
650 FILE *F;
652 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(fn));
654 F = fopen(fn,"rb");
655 if (F==NULL) {
656 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
657 return;
659 _wine_loadsubreg(F,hkey,fn);
660 fclose(F);
663 /******************************************************************************
664 * _flush_registry [Internal]
666 * This function allow to flush section of the internal registry. It is mainly
667 * implements to fix a problem with the global HKU and the local HKU.
668 * Those two files are read to build the HKU\.Default branch to finaly copy
669 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
670 * all the global HKU are saved onto the user's personal version of HKU hive.
671 * which is bad...
674 static void _flush_registry( HKEY hkey )
676 WCHAR name[MAX_PATH];
678 for (;;)
680 HKEY subkey;
681 /* FIXME: we assume that deleting a key will move the other ones up, */
682 /* so that we can always use index 0 until there are no more keys */
683 if (RegEnumKeyW( hkey, 0, name, sizeof(name) ) != ERROR_SUCCESS) break;
684 if (RegOpenKeyW( hkey, name, &subkey ) != ERROR_SUCCESS) break;
685 _flush_registry( subkey );
686 if (RegDeleteKeyW( subkey, NULL ) != ERROR_SUCCESS) break;
687 RegCloseKey( subkey );
692 /******************************************************************************
693 * _copy_registry [Internal]
695 static void _copy_registry( HKEY from, HKEY to )
697 int index;
698 HKEY subkey;
699 FILETIME ft;
700 DWORD type, name_len, len;
701 static WCHAR name[MAX_PATH];
702 static BYTE data[2048];
704 /* copy values */
705 index = 0;
706 for (;;)
708 len = sizeof(data);
709 name_len = sizeof(name);
710 if (RegEnumValueW( from, index++, name, &name_len,
711 NULL, &type, data, &len ) != ERROR_SUCCESS) break;
712 RegSetValueW( to, name, type, (LPCWSTR)data, len );
715 /* copy subkeys */
716 index = 0;
717 for (;;)
719 name_len = sizeof(name);
720 if (RegEnumKeyExW( from, index++, name, &name_len,
721 NULL, NULL, 0, &ft ) != ERROR_SUCCESS)
722 break;
723 if (RegOpenKeyW( from, name, &subkey ) == ERROR_SUCCESS)
725 HKEY newsub;
726 if (RegCreateKeyW( to, name, &newsub ) == ERROR_SUCCESS)
728 _copy_registry( subkey, newsub );
729 RegCloseKey( newsub );
731 RegCloseKey( subkey );
737 /* WINDOWS 95 REGISTRY LOADER */
739 * Structure of a win95 registry database.
740 * main header:
741 * 0 : "CREG" - magic
742 * 4 : DWORD version
743 * 8 : DWORD offset_of_RGDB_part
744 * 0C..0F: ? (someone fill in please)
745 * 10: WORD number of RGDB blocks
746 * 12: WORD ?
747 * 14: WORD always 0000?
748 * 16: WORD always 0001?
749 * 18..1F: ? (someone fill in please)
751 * 20: RGKN_section:
752 * header:
753 * 0 : "RGKN" - magic
754 * 4 : DWORD offset to first RGDB section
755 * 8 : DWORD offset to the root record
756 * C..0x1B: ? (fill in)
757 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
759 * Disk Key Entry Structure:
760 * 00: DWORD - Free entry indicator(?)
761 * 04: DWORD - Hash = sum of bytes of keyname
762 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
763 * 0C: DWORD - disk address of PreviousLevel Key.
764 * 10: DWORD - disk address of Next Sublevel Key.
765 * 14: DWORD - disk address of Next Key (on same level).
766 * DKEP>18: WORD - Nr, Low Significant part.
767 * 1A: WORD - Nr, High Significant part.
769 * The disk address always points to the nr part of the previous key entry
770 * of the referenced key. Don't ask me why, or even if I got this correct
771 * from staring at 1kg of hexdumps. (DKEP)
773 * The High significant part of the structure seems to equal the number
774 * of the RGDB section. The low significant part is a unique ID within
775 * that RGDB section
777 * There are two minor corrections to the position of that structure.
778 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
779 * the DKE reread from there.
780 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
781 * CPS - I have not experienced the above phenomenon in my registry files
783 * RGDB_section:
784 * 00: "RGDB" - magic
785 * 04: DWORD offset to next RGDB section
786 * 08: DWORD ?
787 * 0C: WORD always 000d?
788 * 0E: WORD RGDB block number
789 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
790 * 14..1F: ?
791 * 20.....: disk keys
793 * disk key:
794 * 00: DWORD nextkeyoffset - offset to the next disk key structure
795 * 08: WORD nrLS - low significant part of NR
796 * 0A: WORD nrHS - high significant part of NR
797 * 0C: DWORD bytesused - bytes used in this structure.
798 * 10: WORD name_len - length of name in bytes. without \0
799 * 12: WORD nr_of_values - number of values.
800 * 14: char name[name_len] - name string. No \0.
801 * 14+name_len: disk values
802 * nextkeyoffset: ... next disk key
804 * disk value:
805 * 00: DWORD type - value type (hmm, could be WORD too)
806 * 04: DWORD - unknown, usually 0
807 * 08: WORD namelen - length of Name. 0 means name=NULL
808 * 0C: WORD datalen - length of Data.
809 * 10: char name[namelen] - name, no \0
810 * 10+namelen: BYTE data[datalen] - data, without \0 if string
811 * 10+namelen+datalen: next values or disk key
813 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
814 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
815 * structure) and reading another RGDB_section.
816 * repeat until end of file.
818 * An interesting relationship exists in RGDB_section. The value at offset
819 * 10 equals the value at offset 4 minus the value at offset 8. I have no
820 * idea at the moment what this means. (Kevin Cozens)
822 * FIXME: this description needs some serious help, yes.
825 struct _w95keyvalue {
826 unsigned long type;
827 unsigned short datalen;
828 char *name;
829 unsigned char *data;
830 unsigned long x1;
831 int lastmodified;
834 struct _w95key {
835 char *name;
836 int nrofvals;
837 struct _w95keyvalue *values;
838 struct _w95key *prevlvl;
839 struct _w95key *nextsub;
840 struct _w95key *next;
844 struct _w95_info {
845 char *rgknbuffer;
846 int rgknsize;
847 char *rgdbbuffer;
848 int rgdbsize;
849 int depth;
850 int lastmodified;
854 /******************************************************************************
855 * _w95_processKey [Internal]
857 static HKEY _w95_processKey ( HKEY hkey, int nrLS, int nrMS, struct _w95_info *info )
860 /* Disk Key Header structure (RGDB part) */
861 struct dkh {
862 unsigned long nextkeyoff;
863 unsigned short nrLS;
864 unsigned short nrMS;
865 unsigned long bytesused;
866 unsigned short keynamelen;
867 unsigned short values;
868 unsigned long xx1;
869 /* keyname */
870 /* disk key values or nothing */
872 /* Disk Key Value structure */
873 struct dkv {
874 unsigned long type;
875 unsigned long x1;
876 unsigned short valnamelen;
877 unsigned short valdatalen;
878 /* valname, valdata */
882 struct dkh dkh;
883 int bytesread = 0;
884 char *rgdbdata = info->rgdbbuffer;
885 int nbytes = info->rgdbsize;
886 char *curdata = rgdbdata;
887 char *end = rgdbdata + nbytes;
888 int off_next_rgdb;
889 char *next = rgdbdata;
890 int nrgdb, i;
891 HKEY subkey;
893 do {
894 curdata = next;
895 if (strncmp(curdata, "RGDB", 4)) return 0;
897 memcpy(&off_next_rgdb,curdata+4,4);
898 next = curdata + off_next_rgdb;
899 nrgdb = (int) *((short *)curdata + 7);
901 } while (nrgdb != nrMS && (next < end));
903 /* curdata now points to the start of the right RGDB section */
904 curdata += 0x20;
906 #define XREAD(whereto,len) \
907 if ((curdata + len) <= end) {\
908 memcpy(whereto,curdata,len);\
909 curdata+=len;\
910 bytesread+=len;\
913 while (curdata < next) {
914 struct dkh *xdkh = (struct dkh*)curdata;
916 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
917 if (xdkh->nrLS == nrLS) {
918 memcpy(&dkh,xdkh,sizeof(dkh));
919 curdata += sizeof(dkh);
920 break;
922 curdata += xdkh->nextkeyoff;
925 if (dkh.nrLS != nrLS) return 0;
927 if (nrgdb != dkh.nrMS)
928 return 0;
930 assert((dkh.keynamelen<2) || curdata[0]);
931 subkey=_find_or_add_key(hkey,strcvtA2W(curdata, dkh.keynamelen));
932 curdata += dkh.keynamelen;
934 for (i=0;i< dkh.values; i++) {
935 struct dkv dkv;
936 LPBYTE data;
937 int len;
938 LPWSTR name;
940 XREAD(&dkv,sizeof(dkv));
942 name = strcvtA2W(curdata, dkv.valnamelen);
943 curdata += dkv.valnamelen;
945 if ((1 << dkv.type) & UNICONVMASK) {
946 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
947 len = 2*(dkv.valdatalen + 1);
948 } else {
949 /* I don't think we want to NULL terminate all data */
950 data = xmalloc(dkv.valdatalen);
951 memcpy (data, curdata, dkv.valdatalen);
952 len = dkv.valdatalen;
955 curdata += dkv.valdatalen;
957 _find_or_add_value( subkey, name, dkv.type, data, len );
959 return subkey;
962 /******************************************************************************
963 * _w95_walkrgkn [Internal]
965 static void _w95_walkrgkn( HKEY prevkey, char *off,
966 struct _w95_info *info )
969 /* Disk Key Entry structure (RGKN part) */
970 struct dke {
971 unsigned long x1;
972 unsigned long x2;
973 unsigned long x3;/*usually 0xFFFFFFFF */
974 unsigned long prevlvl;
975 unsigned long nextsub;
976 unsigned long next;
977 unsigned short nrLS;
978 unsigned short nrMS;
979 } *dke = (struct dke *)off;
980 HKEY subkey;
982 if (dke == NULL) {
983 dke = (struct dke *) ((char *)info->rgknbuffer);
986 subkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
988 if (dke->nextsub != -1 &&
989 ((dke->nextsub - 0x20) < info->rgknsize)
990 && (dke->nextsub > 0x20)) {
992 _w95_walkrgkn(subkey ? subkey : prevkey, /* XXX <-- This is a hack*/
993 info->rgknbuffer + dke->nextsub - 0x20,
994 info);
996 if (subkey) RegCloseKey( subkey );
998 if (dke->next != -1 &&
999 ((dke->next - 0x20) < info->rgknsize) &&
1000 (dke->next > 0x20)) {
1001 _w95_walkrgkn(prevkey,
1002 info->rgknbuffer + dke->next - 0x20,
1003 info);
1008 /******************************************************************************
1009 * _w95_loadreg [Internal]
1011 static void _w95_loadreg( char* fn, HKEY hkey )
1013 HFILE hfd;
1014 char magic[5];
1015 unsigned long where,version,rgdbsection,end;
1016 struct _w95_info info;
1017 OFSTRUCT ofs;
1018 BY_HANDLE_FILE_INFORMATION hfdinfo;
1020 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1021 hfd=OpenFile(fn,&ofs,OF_READ);
1022 if (hfd==HFILE_ERROR)
1023 return;
1024 magic[4]=0;
1025 if (4!=_lread(hfd,magic,4))
1026 return;
1027 if (strcmp(magic,"CREG")) {
1028 WARN_(reg)("%s is not a w95 registry.\n",fn);
1029 return;
1031 if (4!=_lread(hfd,&version,4))
1032 return;
1033 if (4!=_lread(hfd,&rgdbsection,4))
1034 return;
1035 if (-1==_llseek(hfd,0x20,SEEK_SET))
1036 return;
1037 if (4!=_lread(hfd,magic,4))
1038 return;
1039 if (strcmp(magic,"RGKN")) {
1040 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1041 return;
1044 /* STEP 1: Keylink structures */
1045 if (-1==_llseek(hfd,0x40,SEEK_SET))
1046 return;
1047 where = 0x40;
1048 end = rgdbsection;
1050 info.rgknsize = end - where;
1051 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1052 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1053 return;
1055 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1056 return;
1058 end = hfdinfo.nFileSizeLow;
1059 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1061 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1062 return;
1064 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1065 info.rgdbsize = end - rgdbsection;
1067 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1068 return;
1069 _lclose(hfd);
1071 _w95_walkrgkn(hkey, NULL, &info);
1073 free (info.rgdbbuffer);
1074 free (info.rgknbuffer);
1078 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1081 reghack - windows 3.11 registry data format demo program.
1083 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1084 a combined hash table and tree description, and finally a text table.
1086 The header is obvious from the struct header. The taboff1 and taboff2
1087 fields are always 0x20, and their usage is unknown.
1089 The 8-byte entry table has various entry types.
1091 tabent[0] is a root index. The second word has the index of the root of
1092 the directory.
1093 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1094 the index of the key/value that has that hash. Data with the same
1095 hash value are on a circular list. The other three words in the
1096 hash entry are always zero.
1097 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1098 entry: dirent and keyent/valent. They are identified by context.
1099 tabent[freeidx] is the first free entry. The first word in a free entry
1100 is the index of the next free entry. The last has 0 as a link.
1101 The other three words in the free list are probably irrelevant.
1103 Entries in text table are preceeded by a word at offset-2. This word
1104 has the value (2*index)+1, where index is the referring keyent/valent
1105 entry in the table. I have no suggestion for the 2* and the +1.
1106 Following the word, there are N bytes of data, as per the keyent/valent
1107 entry length. The offset of the keyent/valent entry is from the start
1108 of the text table to the first data byte.
1110 This information is not available from Microsoft. The data format is
1111 deduced from the reg.dat file by me. Mistakes may
1112 have been made. I claim no rights and give no guarantees for this program.
1114 Tor Sjøwall, tor@sn.no
1117 /* reg.dat header format */
1118 struct _w31_header {
1119 char cookie[8]; /* 'SHCC3.10' */
1120 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1121 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1122 unsigned long tabcnt; /* number of entries in index table */
1123 unsigned long textoff; /* offset of text part */
1124 unsigned long textsize; /* byte size of text part */
1125 unsigned short hashsize; /* hash size */
1126 unsigned short freeidx; /* free index */
1129 /* generic format of table entries */
1130 struct _w31_tabent {
1131 unsigned short w0, w1, w2, w3;
1134 /* directory tabent: */
1135 struct _w31_dirent {
1136 unsigned short sibling_idx; /* table index of sibling dirent */
1137 unsigned short child_idx; /* table index of child dirent */
1138 unsigned short key_idx; /* table index of key keyent */
1139 unsigned short value_idx; /* table index of value valent */
1142 /* key tabent: */
1143 struct _w31_keyent {
1144 unsigned short hash_idx; /* hash chain index for string */
1145 unsigned short refcnt; /* reference count */
1146 unsigned short length; /* length of string */
1147 unsigned short string_off; /* offset of string in text table */
1150 /* value tabent: */
1151 struct _w31_valent {
1152 unsigned short hash_idx; /* hash chain index for string */
1153 unsigned short refcnt; /* reference count */
1154 unsigned short length; /* length of string */
1155 unsigned short string_off; /* offset of string in text table */
1158 /* recursive helper function to display a directory tree */
1159 void
1160 __w31_dumptree( unsigned short idx,
1161 unsigned char *txt,
1162 struct _w31_tabent *tab,
1163 struct _w31_header *head,
1164 HKEY hkey,
1165 time_t lastmodified,
1166 int level
1168 struct _w31_dirent *dir;
1169 struct _w31_keyent *key;
1170 struct _w31_valent *val;
1171 HKEY subkey = 0;
1172 static char tail[400];
1174 while (idx!=0) {
1175 dir=(struct _w31_dirent*)&tab[idx];
1177 if (dir->key_idx) {
1178 key = (struct _w31_keyent*)&tab[dir->key_idx];
1180 memcpy(tail,&txt[key->string_off],key->length);
1181 tail[key->length]='\0';
1182 /* all toplevel entries AND the entries in the
1183 * toplevel subdirectory belong to \SOFTWARE\Classes
1185 if (!level && !lstrcmpA(tail,".classes")) {
1186 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1187 idx=dir->sibling_idx;
1188 continue;
1190 if (subkey) RegCloseKey( subkey );
1191 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1192 /* only add if leaf node or valued node */
1193 if (dir->value_idx!=0||dir->child_idx==0) {
1194 if (dir->value_idx) {
1195 val=(struct _w31_valent*)&tab[dir->value_idx];
1196 memcpy(tail,&txt[val->string_off],val->length);
1197 tail[val->length]='\0';
1198 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1201 } else {
1202 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1204 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1205 idx=dir->sibling_idx;
1207 if (subkey) RegCloseKey( subkey );
1211 /******************************************************************************
1212 * _w31_loadreg [Internal]
1214 void _w31_loadreg(void) {
1215 HFILE hf;
1216 struct _w31_header head;
1217 struct _w31_tabent *tab;
1218 unsigned char *txt;
1219 int len;
1220 OFSTRUCT ofs;
1221 BY_HANDLE_FILE_INFORMATION hfinfo;
1222 time_t lastmodified;
1224 TRACE_(reg)("(void)\n");
1226 hf = OpenFile("reg.dat",&ofs,OF_READ);
1227 if (hf==HFILE_ERROR)
1228 return;
1230 /* read & dump header */
1231 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1232 ERR_(reg)("reg.dat is too short.\n");
1233 _lclose(hf);
1234 return;
1236 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1237 ERR_(reg)("reg.dat has bad signature.\n");
1238 _lclose(hf);
1239 return;
1242 len = head.tabcnt * sizeof(struct _w31_tabent);
1243 /* read and dump index table */
1244 tab = xmalloc(len);
1245 if (len!=_lread(hf,tab,len)) {
1246 ERR_(reg)("couldn't read %d bytes.\n",len);
1247 free(tab);
1248 _lclose(hf);
1249 return;
1252 /* read text */
1253 txt = xmalloc(head.textsize);
1254 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1255 ERR_(reg)("couldn't seek to textblock.\n");
1256 free(tab);
1257 free(txt);
1258 _lclose(hf);
1259 return;
1261 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1262 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1263 free(tab);
1264 free(txt);
1265 _lclose(hf);
1266 return;
1269 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1270 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1271 free(tab);
1272 free(txt);
1273 _lclose(hf);
1274 return;
1276 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1277 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1278 free(tab);
1279 free(txt);
1280 _lclose(hf);
1281 return;
1285 /**********************************************************************************
1286 * SHELL_LoadRegistry [Internal]
1288 void SHELL_LoadRegistry( void )
1290 struct set_registry_levels_request *req = get_req_buffer();
1291 int save_timeout;
1292 char *fn, *home;
1293 HKEY hkey;
1295 TRACE_(reg)("(void)\n");
1297 REGISTRY_Init();
1299 /* set level to 0 for loading system files */
1300 req->current = 0;
1301 req->saving = 0;
1302 req->version = 1;
1303 server_call( REQ_SET_REGISTRY_LEVELS );
1305 if (PROFILE_GetWineIniBool ("registry", "LoadWindowsRegistryFiles", 1))
1307 /* Load windows 3.1 entries */
1308 _w31_loadreg();
1309 /* Load windows 95 entries */
1310 _w95_loadreg("C:\\system.1st", HKEY_LOCAL_MACHINE);
1311 _w95_loadreg("system.dat", HKEY_LOCAL_MACHINE);
1312 _w95_loadreg("user.dat", HKEY_USERS);
1315 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1318 * Load the global HKU hive directly from sysconfdir
1320 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1323 * Load the global machine defaults directly form sysconfdir
1325 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1328 /* set level to 1 for loading user files */
1329 req->current = 1;
1330 req->saving = 0;
1331 req->version = 1;
1332 server_call( REQ_SET_REGISTRY_LEVELS );
1335 * Load the user saved registries
1337 if (!(home = getenv( "HOME" )))
1338 WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1339 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1342 * Load user's personal versions of global HKU/.Default keys
1344 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1345 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1346 strcpy(fn, home);
1347 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1348 _wine_loadreg( HKEY_USERS, fn );
1349 free(fn);
1351 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1352 strcpy(fn, home);
1353 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1354 _wine_loadreg( HKEY_CURRENT_USER, fn );
1355 free(fn);
1358 * Load HKLM, attempt to get the registry location from the config
1359 * file first, if exist, load and keep going.
1361 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1362 strcpy(fn,home);
1363 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1364 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1365 free(fn);
1369 * Load HKCU, get the registry location from the config
1370 * file, if exist, load and keep going.
1372 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1374 fn = xmalloc( MAX_PATHNAME_LEN );
1375 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1376 fn, MAX_PATHNAME_LEN - 1))
1378 _wine_loadreg( HKEY_CURRENT_USER, fn );
1380 free (fn);
1382 * Load HKU, get the registry location from the config
1383 * file, if exist, load and keep going.
1385 fn = xmalloc ( MAX_PATHNAME_LEN );
1386 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1387 fn, MAX_PATHNAME_LEN - 1))
1389 _wine_loadreg( HKEY_USERS, fn );
1391 free (fn);
1393 * Load HKLM, get the registry location from the config
1394 * file, if exist, load and keep going.
1396 fn = xmalloc ( MAX_PATHNAME_LEN );
1397 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1398 fn, MAX_PATHNAME_LEN - 1))
1400 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1402 free (fn);
1406 * Obtain the handle of the HKU\.Default key.
1407 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1409 if (RegCreateKeyA(HKEY_USERS,".Default",&hkey) != ERROR_SUCCESS)
1410 WARN_(reg)("Could not create global user default key\n");
1411 else
1412 _copy_registry( hkey, HKEY_CURRENT_USER );
1413 RegCloseKey(hkey);
1416 * Since HKU is built from the global HKU and the local user HKU file we must
1417 * flush the HKU tree we have built at this point otherwise the part brought
1418 * in from the global HKU is saved into the local HKU. To avoid this
1419 * useless dupplication of HKU keys we reread the local HKU key.
1422 /* Allways flush the HKU hive and reload it only with user's personal HKU */
1423 _flush_registry( HKEY_USERS );
1425 /* Reload user's local HKU hive */
1426 if (home && PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
1428 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
1429 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
1431 strcpy(fn,home);
1432 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1434 _wine_loadreg( HKEY_USERS, fn );
1436 free(fn);
1440 * Make sure the update mode is there
1442 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
1444 DWORD junk,type,len;
1445 char data[5];
1447 len=4;
1448 if (( RegQueryValueExA(
1449 hkey,
1450 VAL_SAVEUPDATED,
1451 &junk,
1452 &type,
1453 data,
1454 &len) != ERROR_SUCCESS) || (type != REG_SZ))
1456 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1459 RegCloseKey(hkey);
1462 if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1464 SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1469 /********************* API FUNCTIONS ***************************************/
1474 /******************************************************************************
1475 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1476 * Immediately writes key to registry.
1477 * Only returns after data has been written to disk.
1479 * FIXME: does it really wait until data is written ?
1481 * PARAMS
1482 * hkey [I] Handle of key to write
1484 * RETURNS
1485 * Success: ERROR_SUCCESS
1486 * Failure: Error code
1488 DWORD WINAPI RegFlushKey( HKEY hkey )
1490 FIXME( "(%x): stub\n", hkey );
1491 return ERROR_SUCCESS;
1494 /******************************************************************************
1495 * RegConnectRegistry32W [ADVAPI32.128]
1497 * PARAMS
1498 * lpMachineName [I] Address of name of remote computer
1499 * hHey [I] Predefined registry handle
1500 * phkResult [I] Address of buffer for remote registry handle
1502 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1503 LPHKEY phkResult )
1505 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1507 if (!lpMachineName || !*lpMachineName) {
1508 /* Use the local machine name */
1509 return RegOpenKey16( hKey, "", phkResult );
1512 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
1513 return ERROR_BAD_NETPATH;
1517 /******************************************************************************
1518 * RegConnectRegistry32A [ADVAPI32.127]
1520 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1522 DWORD ret;
1523 LPWSTR machineW = strdupA2W(machine);
1524 ret = RegConnectRegistryW( machineW, hkey, reskey );
1525 free(machineW);
1526 return ret;
1530 /******************************************************************************
1531 * RegGetKeySecurity [ADVAPI32.144]
1532 * Retrieves a copy of security descriptor protecting the registry key
1534 * PARAMS
1535 * hkey [I] Open handle of key to set
1536 * SecurityInformation [I] Descriptor contents
1537 * pSecurityDescriptor [O] Address of descriptor for key
1538 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1540 * RETURNS
1541 * Success: ERROR_SUCCESS
1542 * Failure: Error code
1544 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1545 SECURITY_INFORMATION SecurityInformation,
1546 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1547 LPDWORD lpcbSecurityDescriptor )
1549 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1550 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1552 /* FIXME: Check for valid SecurityInformation values */
1554 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1555 return ERROR_INSUFFICIENT_BUFFER;
1557 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1558 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1560 return ERROR_SUCCESS;
1564 /******************************************************************************
1565 * RegNotifyChangeKeyValue [ADVAPI32.???]
1567 * PARAMS
1568 * hkey [I] Handle of key to watch
1569 * fWatchSubTree [I] Flag for subkey notification
1570 * fdwNotifyFilter [I] Changes to be reported
1571 * hEvent [I] Handle of signaled event
1572 * fAsync [I] Flag for asynchronous reporting
1574 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1575 DWORD fdwNotifyFilter, HANDLE hEvent,
1576 BOOL fAsync )
1578 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1579 hEvent,fAsync);
1580 return ERROR_SUCCESS;
1584 /******************************************************************************
1585 * RegUnLoadKey32W [ADVAPI32.173]
1587 * PARAMS
1588 * hkey [I] Handle of open key
1589 * lpSubKey [I] Address of name of subkey to unload
1591 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1593 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1594 return ERROR_SUCCESS;
1598 /******************************************************************************
1599 * RegUnLoadKey32A [ADVAPI32.172]
1601 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1603 LONG ret;
1604 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1605 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1606 if(lpSubKeyW) free(lpSubKeyW);
1607 return ret;
1611 /******************************************************************************
1612 * RegSetKeySecurity [ADVAPI32.167]
1614 * PARAMS
1615 * hkey [I] Open handle of key to set
1616 * SecurityInfo [I] Descriptor contents
1617 * pSecurityDesc [I] Address of descriptor for key
1619 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1620 PSECURITY_DESCRIPTOR pSecurityDesc )
1622 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1624 /* It seems to perform this check before the hkey check */
1625 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1626 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1627 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1628 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1629 /* Param OK */
1630 } else
1631 return ERROR_INVALID_PARAMETER;
1633 if (!pSecurityDesc)
1634 return ERROR_INVALID_PARAMETER;
1636 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1638 return ERROR_SUCCESS;
1642 /******************************************************************************
1643 * RegRestoreKey32W [ADVAPI32.164]
1645 * PARAMS
1646 * hkey [I] Handle of key where restore begins
1647 * lpFile [I] Address of filename containing saved tree
1648 * dwFlags [I] Optional flags
1650 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1652 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1654 /* It seems to do this check before the hkey check */
1655 if (!lpFile || !*lpFile)
1656 return ERROR_INVALID_PARAMETER;
1658 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1660 /* Check for file existence */
1662 return ERROR_SUCCESS;
1666 /******************************************************************************
1667 * RegRestoreKey32A [ADVAPI32.163]
1669 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1671 LONG ret;
1672 LPWSTR lpFileW = strdupA2W(lpFile);
1673 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1674 if(lpFileW) free(lpFileW);
1675 return ret;
1679 /******************************************************************************
1680 * RegReplaceKey32W [ADVAPI32.162]
1682 * PARAMS
1683 * hkey [I] Handle of open key
1684 * lpSubKey [I] Address of name of subkey
1685 * lpNewFile [I] Address of filename for file with new data
1686 * lpOldFile [I] Address of filename for backup file
1688 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1689 LPCWSTR lpOldFile )
1691 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1692 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1693 return ERROR_SUCCESS;
1697 /******************************************************************************
1698 * RegReplaceKey32A [ADVAPI32.161]
1700 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1701 LPCSTR lpOldFile )
1703 LONG ret;
1704 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1705 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1706 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1707 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1708 free(lpOldFileW);
1709 free(lpNewFileW);
1710 free(lpSubKeyW);
1711 return ret;
1719 /* 16-bit functions */
1721 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1722 * some programs. Do not remove those cases. -MM
1724 static inline void fix_win16_hkey( HKEY *hkey )
1726 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1729 /******************************************************************************
1730 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1732 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1734 fix_win16_hkey( &hkey );
1735 return RegEnumKeyA( hkey, index, name, name_len );
1738 /******************************************************************************
1739 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1741 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1743 fix_win16_hkey( &hkey );
1744 return RegOpenKeyA( hkey, name, retkey );
1747 /******************************************************************************
1748 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1750 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1752 fix_win16_hkey( &hkey );
1753 return RegCreateKeyA( hkey, name, retkey );
1756 /******************************************************************************
1757 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1759 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1761 fix_win16_hkey( &hkey );
1762 return RegDeleteKeyA( hkey, name );
1765 /******************************************************************************
1766 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1768 DWORD WINAPI RegCloseKey16( HKEY hkey )
1770 fix_win16_hkey( &hkey );
1771 return RegCloseKey( hkey );
1774 /******************************************************************************
1775 * RegSetValue16 [KERNEL.221] [SHELL.5]
1777 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1779 fix_win16_hkey( &hkey );
1780 return RegSetValueA( hkey, name, type, data, count );
1783 /******************************************************************************
1784 * RegDeleteValue16 [KERNEL.222]
1786 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1788 fix_win16_hkey( &hkey );
1789 return RegDeleteValueA( hkey, name );
1792 /******************************************************************************
1793 * RegEnumValue16 [KERNEL.223]
1795 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1796 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1798 fix_win16_hkey( &hkey );
1799 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1802 /******************************************************************************
1803 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1805 * NOTES
1806 * Is this HACK still applicable?
1808 * HACK
1809 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1810 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1811 * Aldus FH4)
1813 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1815 fix_win16_hkey( &hkey );
1816 if (count) *count &= 0xffff;
1817 return RegQueryValueA( hkey, name, data, count );
1820 /******************************************************************************
1821 * RegQueryValueEx16 [KERNEL.225]
1823 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1824 LPBYTE data, LPDWORD count )
1826 fix_win16_hkey( &hkey );
1827 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1830 /******************************************************************************
1831 * RegSetValueEx16 [KERNEL.226]
1833 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1834 CONST BYTE *data, DWORD count )
1836 fix_win16_hkey( &hkey );
1837 return RegSetValueExA( hkey, name, reserved, type, data, count );