Allow the file names and paths for the registry files (user.reg and
[wine/multimedia.git] / misc / registry.c
blobfa0454de124a10154d34bde8cf8273679773cb30
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
7 * December 21, 1997 - Kevin Cozens
8 * Fixed bugs in the _w95_loadreg() function. Added extra information
9 * regarding the format of the Windows '95 registry files.
11 * NOTES
12 * When changing this file, please re-run the regtest program to ensure
13 * the conditions are handled properly.
15 * TODO
16 * Security access
17 * Option handling
18 * Time for RegEnumKey*, RegQueryInfoKey*
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/fcntl.h>
29 #include <sys/stat.h>
30 #include <pwd.h>
31 #include <assert.h>
32 #include <time.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wine/winbase16.h"
36 #include "wine/winestring.h"
37 #include "winerror.h"
38 #include "file.h"
39 #include "heap.h"
40 #include "debug.h"
41 #include "xmalloc.h"
42 #include "winreg.h"
43 #include "winversion.h"
45 static void REGISTRY_Init(void);
46 /* FIXME: following defines should be configured global ... */
48 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
49 #define WINE_PREFIX "/.wine"
50 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
51 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
53 /* relative in ~user/.wine/ : */
54 #define SAVE_CURRENT_USER "user.reg"
55 #define SAVE_LOCAL_MACHINE "system.reg"
57 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
58 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
60 /* one value of a key */
61 typedef struct tagKEYVALUE
63 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
64 DWORD type; /* type of value */
65 DWORD len; /* length of data in BYTEs */
66 DWORD lastmodified; /* time of seconds since 1.1.1970 */
67 LPBYTE data; /* content, may be strings, binaries, etc. */
68 } KEYVALUE,*LPKEYVALUE;
70 /* a registry key */
71 typedef struct tagKEYSTRUCT
73 LPWSTR keyname; /* name of THIS key (UNICODE) */
74 DWORD flags; /* flags. */
75 LPWSTR class;
76 /* values */
77 DWORD nrofvalues; /* nr of values in THIS key */
78 LPKEYVALUE values; /* values in THIS key */
79 /* key management pointers */
80 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
81 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
82 } KEYSTRUCT, *LPKEYSTRUCT;
85 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
86 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
87 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
88 static KEYSTRUCT *key_users=NULL; /* all users? */
90 /* dynamic, not saved */
91 static KEYSTRUCT *key_performance_data=NULL;
92 static KEYSTRUCT *key_current_config=NULL;
93 static KEYSTRUCT *key_dyn_data=NULL;
95 /* what valuetypes do we need to convert? */
96 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
99 static struct openhandle {
100 LPKEYSTRUCT lpkey;
101 HKEY hkey;
102 REGSAM accessmask;
103 } *openhandles=NULL;
104 static int nrofopenhandles=0;
105 /* Starts after 1 because 0,1 are reserved for Win16 */
106 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
107 HKEYs for remote registry access */
108 static int currenthandle=2;
112 * QUESTION
113 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
114 * If so, can we remove them?
115 * ANSWER
116 * No, the memory handling functions are called very often in here,
117 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
118 * loading 100 times slower. -MM
120 static LPWSTR strdupA2W(LPCSTR src)
122 if(src) {
123 LPWSTR dest=xmalloc(2*strlen(src)+2);
124 lstrcpyAtoW(dest,src);
125 return dest;
127 return NULL;
130 static LPWSTR strdupW(LPCWSTR a) {
131 LPWSTR b;
132 int len;
134 if(a) {
135 len=sizeof(WCHAR)*(lstrlenW(a)+1);
136 b=(LPWSTR)xmalloc(len);
137 memcpy(b,a,len);
138 return b;
140 return NULL;
143 LPWSTR strcvtA2W(LPCSTR src, int nchars)
146 LPWSTR dest = xmalloc (2 * nchars + 2);
148 lstrcpynAtoW(dest,src,nchars+1);
149 dest[nchars] = 0;
150 return dest;
153 * we need to convert A to W with '\0' in strings (MULTI_SZ)
156 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
157 { LPWSTR p = dst;
159 TRACE(reg,"\"%s\" %i\n",src, n);
161 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
163 return dst;
165 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
166 { LPSTR p = dst;
168 TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
170 while (n-- > 0) *p++ = (CHAR)*src++;
172 return dst;
175 static void debug_print_value (LPBYTE lpbData, DWORD type, DWORD len)
176 { if (TRACE_ON(reg) && lpbData)
177 { switch(type)
178 { case REG_SZ:
179 TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
180 break;
182 case REG_DWORD:
183 TRACE(reg," Data(dword)=0x%08lx\n",(DWORD)*lpbData);
184 break;
186 case REG_MULTI_SZ:
187 { int i;
188 LPCWSTR ptr = (LPCWSTR)lpbData;
189 for (i=0;ptr[0];i++)
190 { TRACE(reg, " MULTI_SZ(%i=%s)\n", i, debugstr_w(ptr));
191 ptr += lstrlenW(ptr)+1;
194 break;
196 case REG_BINARY:
197 { char szTemp[100]; /* 3*32 + 3 + 1 */
198 int i;
199 for ( i = 0; i < len ; i++)
200 { sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
201 if (i>=31)
202 { sprintf (&(szTemp[i*3+3]),"...");
203 break;
206 TRACE(reg," Data(raw)=(%s)\n", szTemp);
208 break;
210 default:
211 FIXME(reg, " Unknown data type %ld\n", type);
212 } /* switch */
213 } /* if */
218 /******************************************************************************
219 * is_standard_hkey [Internal]
220 * Determines if a hkey is a standard key
222 static BOOL is_standard_hkey( HKEY hkey )
224 switch(hkey) {
225 case 0x00000000:
226 case 0x00000001:
227 case HKEY_CLASSES_ROOT:
228 case HKEY_CURRENT_CONFIG:
229 case HKEY_CURRENT_USER:
230 case HKEY_LOCAL_MACHINE:
231 case HKEY_USERS:
232 case HKEY_PERFORMANCE_DATA:
233 case HKEY_DYN_DATA:
234 return TRUE;
235 default:
236 return FALSE;
240 /******************************************************************************
241 * add_handle [Internal]
243 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
245 int i;
247 TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
248 /* Check for duplicates */
249 for (i=0;i<nrofopenhandles;i++) {
250 if (openhandles[i].lpkey==lpkey) {
251 /* This is not really an error - the user is allowed to create
252 two (or more) handles to the same key */
253 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
255 if (openhandles[i].hkey==hkey) {
256 WARN(reg, "Adding handle %x twice\n",hkey);
259 openhandles=xrealloc( openhandles,
260 sizeof(struct openhandle)*(nrofopenhandles+1));
262 openhandles[i].lpkey = lpkey;
263 openhandles[i].hkey = hkey;
264 openhandles[i].accessmask = accessmask;
265 nrofopenhandles++;
269 /******************************************************************************
270 * get_handle [Internal]
272 * RETURNS
273 * Success: Pointer to key
274 * Failure: NULL
276 static LPKEYSTRUCT get_handle( HKEY hkey )
278 int i;
280 for (i=0; i<nrofopenhandles; i++)
281 if (openhandles[i].hkey == hkey)
282 return openhandles[i].lpkey;
283 WARN(reg, "Could not find handle 0x%x\n",hkey);
284 return NULL;
288 /******************************************************************************
289 * remove_handle [Internal]
291 * PARAMS
292 * hkey [I] Handle of key to remove
294 * RETURNS
295 * Success: ERROR_SUCCESS
296 * Failure: ERROR_INVALID_HANDLE
298 static DWORD remove_handle( HKEY hkey )
300 int i;
302 for (i=0;i<nrofopenhandles;i++)
303 if (openhandles[i].hkey==hkey)
304 break;
306 if (i == nrofopenhandles) {
307 WARN(reg, "Could not find handle 0x%x\n",hkey);
308 return ERROR_INVALID_HANDLE;
311 memcpy( openhandles+i,
312 openhandles+i+1,
313 sizeof(struct openhandle)*(nrofopenhandles-i-1)
315 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
316 nrofopenhandles--;
317 return ERROR_SUCCESS;
320 /******************************************************************************
321 * lookup_hkey [Internal]
323 * Just as the name says. Creates the root keys on demand, so we can call the
324 * Reg* functions at any time.
326 * RETURNS
327 * Success: Pointer to key structure
328 * Failure: NULL
330 #define ADD_ROOT_KEY(xx) \
331 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
332 memset(xx,'\0',sizeof(KEYSTRUCT));\
333 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
335 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
337 switch (hkey) {
338 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
339 * some programs. Do not remove those cases. -MM
341 case 0x00000000:
342 case 0x00000001:
343 case HKEY_CLASSES_ROOT: {
344 if (!key_classes_root) {
345 HKEY cl_r_hkey;
347 /* calls lookup_hkey recursively, TWICE */
348 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
349 ERR(reg,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
350 exit(1);
352 key_classes_root = lookup_hkey(cl_r_hkey);
354 return key_classes_root;
356 case HKEY_CURRENT_USER:
357 if (!key_current_user) {
358 HKEY c_u_hkey;
359 struct passwd *pwd;
361 pwd=getpwuid(getuid());
362 /* calls lookup_hkey recursively, TWICE */
363 if (pwd && pwd->pw_name) {
364 if (RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey)!=ERROR_SUCCESS) {
365 ERR(reg,"Could not create HU\\%s. This is impossible.\n",pwd->pw_name);
366 exit(1);
368 key_current_user = lookup_hkey(c_u_hkey);
369 } else {
370 /* nothing found, use standalone */
371 ADD_ROOT_KEY(key_current_user);
374 return key_current_user;
375 case HKEY_LOCAL_MACHINE:
376 if (!key_local_machine) {
377 ADD_ROOT_KEY(key_local_machine);
378 REGISTRY_Init();
380 return key_local_machine;
381 case HKEY_USERS:
382 if (!key_users) {
383 ADD_ROOT_KEY(key_users);
385 return key_users;
386 case HKEY_PERFORMANCE_DATA:
387 if (!key_performance_data) {
388 ADD_ROOT_KEY(key_performance_data);
390 return key_performance_data;
391 case HKEY_DYN_DATA:
392 if (!key_dyn_data) {
393 ADD_ROOT_KEY(key_dyn_data);
395 return key_dyn_data;
396 case HKEY_CURRENT_CONFIG:
397 if (!key_current_config) {
398 ADD_ROOT_KEY(key_current_config);
400 return key_current_config;
401 default:
402 return get_handle(hkey);
404 /*NOTREACHED*/
406 #undef ADD_ROOT_KEY
407 /* so we don't accidently access them ... */
408 #define key_current_config NULL NULL
409 #define key_current_user NULL NULL
410 #define key_users NULL NULL
411 #define key_local_machine NULL NULL
412 #define key_classes_root NULL NULL
413 #define key_dyn_data NULL NULL
414 #define key_performance_data NULL NULL
416 /******************************************************************************
417 * split_keypath [Internal]
418 * splits the unicode string 'wp' into an array of strings.
419 * the array is allocated by this function.
420 * Free the array using FREE_KEY_PATH
422 * PARAMS
423 * wp [I] String to split up
424 * wpv [O] Array of pointers to strings
425 * wpc [O] Number of components
427 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
429 int i,j,len;
430 LPWSTR ws;
432 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
434 ws = HEAP_strdupW( SystemHeap, 0, wp );
436 /* We know we have at least one substring */
437 *wpc = 1;
439 /* Replace each backslash with NULL, and increment the count */
440 for (i=0;ws[i];i++) {
441 if (ws[i]=='\\') {
442 ws[i]=0;
443 (*wpc)++;
447 len = i;
449 /* Allocate the space for the array of pointers, leaving room for the
450 NULL at the end */
451 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
452 (*wpv)[0]= ws;
454 /* Assign each pointer to the appropriate character in the string */
455 j = 1;
456 for (i=1;i<len;i++)
457 if (ws[i-1]==0) {
458 (*wpv)[j++]=ws+i;
459 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
462 (*wpv)[j]=NULL;
464 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
469 /******************************************************************************
470 * REGISTRY_Init [Internal]
471 * Registry initialisation, allocates some default keys.
473 static void REGISTRY_Init(void) {
474 HKEY hkey;
475 char buf[200];
477 TRACE(reg,"(void)\n");
479 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
480 RegCloseKey(hkey);
482 /* This was an Open, but since it is called before the real registries
483 are loaded, it was changed to a Create - MTB 980507*/
484 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
485 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
486 RegCloseKey(hkey);
488 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
489 * CurrentVersion
490 * CurrentBuildNumber
491 * CurrentType
492 * string RegisteredOwner
493 * string RegisteredOrganization
496 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
497 * string SysContact
498 * string SysLocation
499 * SysServices
501 if (-1!=gethostname(buf,200)) {
502 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
503 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
504 RegCloseKey(hkey);
509 /************************ SAVE Registry Function ****************************/
511 #define REGISTRY_SAVE_VERSION 0x00000001
513 /* Registry saveformat:
514 * If you change it, increase above number by 1, which will flush
515 * old registry database files.
517 * Global:
518 * "WINE REGISTRY Version %d"
519 * subkeys....
520 * Subkeys:
521 * keyname
522 * valuename=lastmodified,type,data
523 * ...
524 * subkeys
525 * ...
526 * keyname,valuename,stringdata:
527 * the usual ascii characters from 0x00-0xff (well, not 0x00)
528 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
529 * ( "=\\\t" escaped in \uXXXX form.)
530 * type,lastmodified:
531 * int
533 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
535 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
536 * SaveOnlyUpdatedKeys=yes
539 /******************************************************************************
540 * _save_check_tainted [Internal]
542 static int _save_check_tainted( LPKEYSTRUCT lpkey )
544 int tainted;
546 if (!lpkey)
547 return 0;
548 if (lpkey->flags & REG_OPTION_TAINTED)
549 tainted = 1;
550 else
551 tainted = 0;
552 while (lpkey) {
553 if (_save_check_tainted(lpkey->nextsub)) {
554 lpkey->flags |= REG_OPTION_TAINTED;
555 tainted = 1;
557 lpkey = lpkey->next;
559 return tainted;
562 /******************************************************************************
563 * _save_USTRING [Internal]
565 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
567 LPWSTR s;
568 int doescape;
570 if (wstr==NULL)
571 return;
572 s=wstr;
573 while (*s) {
574 doescape=0;
575 if (*s>0xff)
576 doescape = 1;
577 if (*s=='\n')
578 doescape = 1;
579 if (escapeeq && *s=='=')
580 doescape = 1;
581 if (*s=='\\')
582 fputc(*s,F); /* if \\ then put it twice. */
583 if (doescape)
584 fprintf(F,"\\u%04x",*((unsigned short*)s));
585 else
586 fputc(*s,F);
587 s++;
591 /******************************************************************************
592 * _savesubkey [Internal]
594 * NOTES
595 * REG_MULTI_SZ is handled as binary (like in win95) (js)
597 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
599 LPKEYSTRUCT lpxkey;
600 int i,tabs,j;
602 lpxkey = lpkey;
603 while (lpxkey) {
604 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
605 (all || (lpxkey->flags & REG_OPTION_TAINTED))
607 for (tabs=level;tabs--;)
608 fputc('\t',F);
609 _save_USTRING(F,lpxkey->keyname,1);
610 fputs("\n",F);
611 for (i=0;i<lpxkey->nrofvalues;i++) {
612 LPKEYVALUE val=lpxkey->values+i;
614 for (tabs=level+1;tabs--;)
615 fputc('\t',F);
616 _save_USTRING(F,val->name,0);
617 fputc('=',F);
618 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
619 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
620 _save_USTRING(F,(LPWSTR)val->data,0);
621 else
622 for (j=0;j<val->len;j++)
623 fprintf(F,"%02x",*((unsigned char*)val->data+j));
624 fputs("\n",F);
626 /* descend recursively */
627 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
628 return 0;
630 lpxkey=lpxkey->next;
632 return 1;
636 /******************************************************************************
637 * _savesubreg [Internal]
639 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
641 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
642 _save_check_tainted(lpkey->nextsub);
643 return _savesubkey(F,lpkey->nextsub,0,all);
647 /******************************************************************************
648 * _savereg [Internal]
650 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
652 FILE *F;
654 F=fopen(fn,"w");
655 if (F==NULL) {
656 WARN(reg,"Couldn't open %s for writing: %s\n",
657 fn,strerror(errno)
659 return FALSE;
661 if (!_savesubreg(F,lpkey,all)) {
662 fclose(F);
663 unlink(fn);
664 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
665 return FALSE;
667 fclose(F);
668 return TRUE;
672 /******************************************************************************
673 * SHELL_SaveRegistry [Internal]
675 void SHELL_SaveRegistry( void )
677 char *fn;
678 struct passwd *pwd;
679 char buf[4];
680 HKEY hkey;
681 int all;
682 int usedCfgUser = 0;
683 int usedCfgLM = 0;
685 TRACE(reg,"(void)\n");
687 all=0;
688 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
689 strcpy(buf,"yes");
690 } else {
691 DWORD len,junk,type;
693 len=4;
694 if ( (ERROR_SUCCESS!=RegQueryValueExA(
695 hkey,
696 VAL_SAVEUPDATED,
697 &junk,
698 &type,
699 buf,
700 &len
701 ))|| (type!=REG_SZ)
703 strcpy(buf,"yes");
704 RegCloseKey(hkey);
706 if (lstrcmpiA(buf,"yes"))
707 all=1;
709 /* Try saving a config file specified User.reg save/load name */
710 fn = xmalloc( MAX_PATHNAME_LEN );
711 if (PROFILE_GetWineIniString ("Registry", "UserFileName", "", fn, MAX_PATHNAME_LEN - 1)) {
712 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
713 usedCfgUser = 1;
715 free (fn);
717 /* Try saving a config file specified System.reg save/load name*/
718 fn = xmalloc ( MAX_PATHNAME_LEN);
719 if (PROFILE_GetWineIniString ("Registry", "LocalMachineFileName", "", fn, MAX_PATHNAME_LEN - 1)){
720 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
721 usedCfgLM = 1;
723 free (fn);
725 pwd=getpwuid(getuid());
726 if (pwd!=NULL && pwd->pw_dir!=NULL)
728 char *tmp;
730 /* Hack to disable double save */
731 if (usedCfgUser == 0){
733 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
734 strlen(SAVE_CURRENT_USER) + 2 );
735 strcpy(fn,pwd->pw_dir);
736 strcat(fn,WINE_PREFIX);
737 /* create the directory. don't care about errorcodes. */
738 mkdir(fn,0755); /* drwxr-xr-x */
739 strcat(fn,"/"SAVE_CURRENT_USER);
740 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
741 strcpy(tmp,fn);strcat(tmp,".tmp");
742 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
743 if (-1==rename(tmp,fn)) {
744 perror("rename tmp registry");
745 unlink(tmp);
748 free(tmp);
749 free(fn);
753 /* Hack to disable double save */
754 if (usedCfgLM == 0){
756 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
757 strcpy(fn,pwd->pw_dir);
758 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
759 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
760 strcpy(tmp,fn);strcat(tmp,".tmp");
761 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
762 if (-1==rename(tmp,fn)) {
763 perror("rename tmp registry");
764 unlink(tmp);
767 free(tmp);
768 free(fn);
771 } else
772 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
776 /************************ LOAD Registry Function ****************************/
780 /******************************************************************************
781 * _find_or_add_key [Internal]
783 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
785 LPKEYSTRUCT lpxkey,*lplpkey;
787 if ((!keyname) || (keyname[0]==0)) {
788 free(keyname);
789 return lpkey;
791 lplpkey= &(lpkey->nextsub);
792 lpxkey = *lplpkey;
793 while (lpxkey) {
794 if ( (lpxkey->keyname[0]==keyname[0]) &&
795 !lstrcmpiW(lpxkey->keyname,keyname)
797 break;
798 lplpkey = &(lpxkey->next);
799 lpxkey = *lplpkey;
801 if (lpxkey==NULL) {
802 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
803 lpxkey = *lplpkey;
804 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
805 lpxkey->keyname = keyname;
806 } else
807 free(keyname);
808 return lpxkey;
811 /******************************************************************************
812 * _find_or_add_value [Internal]
814 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
815 LPBYTE data, DWORD len, DWORD lastmodified )
817 LPKEYVALUE val=NULL;
818 int i;
820 if (name && !*name) {/* empty string equals default (NULL) value */
821 free(name);
822 name = NULL;
825 for (i=0;i<lpkey->nrofvalues;i++) {
826 val=lpkey->values+i;
827 if (name==NULL) {
828 if (val->name==NULL)
829 break;
830 } else {
831 if ( val->name!=NULL &&
832 val->name[0]==name[0] &&
833 !lstrcmpiW(val->name,name)
835 break;
838 if (i==lpkey->nrofvalues) {
839 lpkey->values = xrealloc(
840 lpkey->values,
841 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
843 val=lpkey->values+i;
844 memset(val,'\0',sizeof(KEYVALUE));
845 val->name = name;
846 } else {
847 if (name)
848 free(name);
850 if (val->lastmodified<lastmodified) {
851 val->lastmodified=lastmodified;
852 val->type = type;
853 val->len = len;
854 if (val->data)
855 free(val->data);
856 val->data = data;
857 } else
858 free(data);
862 /******************************************************************************
863 * _wine_read_line [Internal]
865 * reads a line including dynamically enlarging the readbuffer and throwing
866 * away comments
868 static int _wine_read_line( FILE *F, char **buf, int *len )
870 char *s,*curread;
871 int mylen,curoff;
873 curread = *buf;
874 mylen = *len;
875 **buf = '\0';
876 while (1) {
877 while (1) {
878 s=fgets(curread,mylen,F);
879 if (s==NULL)
880 return 0; /* EOF */
881 if (NULL==(s=strchr(curread,'\n'))) {
882 /* buffer wasn't large enough */
883 curoff = strlen(*buf);
884 *buf = xrealloc(*buf,*len*2);
885 curread = *buf + curoff;
886 mylen = *len; /* we filled up the buffer and
887 * got new '*len' bytes to fill
889 *len = *len * 2;
890 } else {
891 *s='\0';
892 break;
895 /* throw away comments */
896 if (**buf=='#' || **buf==';') {
897 curread = *buf;
898 mylen = *len;
899 continue;
901 if (s) /* got end of line */
902 break;
904 return 1;
908 /******************************************************************************
909 * _wine_read_USTRING [Internal]
911 * converts a char* into a UNICODE string (up to a special char)
912 * and returns the position exactly after that string
914 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
916 char *s;
917 LPWSTR ws;
919 /* read up to "=" or "\0" or "\n" */
920 s = buf;
921 if (*s == '=') {
922 /* empty string is the win3.1 default value(NULL)*/
923 *str = NULL;
924 return s;
926 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
927 ws = *str;
928 while (*s && (*s!='\n') && (*s!='=')) {
929 if (*s!='\\')
930 *ws++=*((unsigned char*)s++);
931 else {
932 s++;
933 if (!*s) {
934 /* Dangling \ ... may only happen if a registry
935 * write was short. FIXME: What do to?
937 break;
939 if (*s=='\\') {
940 *ws++='\\';
941 s++;
942 continue;
944 if (*s!='u') {
945 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
946 *ws++='\\';
947 *ws++=*s++;
948 } else {
949 char xbuf[5];
950 int wc;
952 s++;
953 memcpy(xbuf,s,4);xbuf[4]='\0';
954 if (!sscanf(xbuf,"%x",&wc))
955 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
956 s+=4;
957 *ws++ =(unsigned short)wc;
961 *ws = 0;
962 ws = *str;
963 if (*ws)
964 *str = strdupW(*str);
965 else
966 *str = NULL;
967 free(ws);
968 return s;
972 /******************************************************************************
973 * _wine_loadsubkey [Internal]
975 * NOTES
976 * It seems like this is returning a boolean. Should it?
978 * RETURNS
979 * Success: 1
980 * Failure: 0
982 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
983 int *buflen, DWORD optflag )
985 LPKEYSTRUCT lpxkey;
986 int i;
987 char *s;
988 LPWSTR name;
990 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
991 *buflen, optflag);
993 lpkey->flags |= optflag;
995 /* Good. We already got a line here ... so parse it */
996 lpxkey = NULL;
997 while (1) {
998 i=0;s=*buf;
999 while (*s=='\t') {
1000 s++;
1001 i++;
1003 if (i>level) {
1004 if (lpxkey==NULL) {
1005 WARN(reg,"Got a subhierarchy without resp. key?\n");
1006 return 0;
1008 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1009 continue;
1012 /* let the caller handle this line */
1013 if (i<level || **buf=='\0')
1014 return 1;
1016 /* it can be: a value or a keyname. Parse the name first */
1017 s=_wine_read_USTRING(s,&name);
1019 /* switch() default: hack to avoid gotos */
1020 switch (0) {
1021 default:
1022 if (*s=='\0') {
1023 lpxkey=_find_or_add_key(lpkey,name);
1024 } else {
1025 LPBYTE data;
1026 int len,lastmodified,type;
1028 if (*s!='=') {
1029 WARN(reg,"Unexpected character: %c\n",*s);
1030 break;
1032 s++;
1033 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1034 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1035 break;
1037 /* skip the 2 , */
1038 s=strchr(s,',');s++;
1039 s=strchr(s,',');s++;
1040 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1041 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1042 if (data)
1043 len = lstrlenW((LPWSTR)data)*2+2;
1044 else
1045 len = 0;
1046 } else {
1047 len=strlen(s)/2;
1048 data = (LPBYTE)xmalloc(len+1);
1049 for (i=0;i<len;i++) {
1050 data[i]=0;
1051 if (*s>='0' && *s<='9')
1052 data[i]=(*s-'0')<<4;
1053 if (*s>='a' && *s<='f')
1054 data[i]=(*s-'a'+'\xa')<<4;
1055 if (*s>='A' && *s<='F')
1056 data[i]=(*s-'A'+'\xa')<<4;
1057 s++;
1058 if (*s>='0' && *s<='9')
1059 data[i]|=*s-'0';
1060 if (*s>='a' && *s<='f')
1061 data[i]|=*s-'a'+'\xa';
1062 if (*s>='A' && *s<='F')
1063 data[i]|=*s-'A'+'\xa';
1064 s++;
1067 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1070 /* read the next line */
1071 if (!_wine_read_line(F,buf,buflen))
1072 return 1;
1074 return 1;
1078 /******************************************************************************
1079 * _wine_loadsubreg [Internal]
1081 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1083 int ver;
1084 char *buf;
1085 int buflen;
1087 buf=xmalloc(10);buflen=10;
1088 if (!_wine_read_line(F,&buf,&buflen)) {
1089 free(buf);
1090 return 0;
1092 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1093 free(buf);
1094 return 0;
1096 if (ver!=REGISTRY_SAVE_VERSION) {
1097 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1098 free(buf);
1099 return 0;
1101 if (!_wine_read_line(F,&buf,&buflen)) {
1102 free(buf);
1103 return 0;
1105 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1106 free(buf);
1107 return 0;
1109 free(buf);
1110 return 1;
1114 /******************************************************************************
1115 * _wine_loadreg [Internal]
1117 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1119 FILE *F;
1121 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1123 F = fopen(fn,"rb");
1124 if (F==NULL) {
1125 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1126 return;
1128 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1129 fclose(F);
1130 unlink(fn);
1131 return;
1133 fclose(F);
1137 /******************************************************************************
1138 * _copy_registry [Internal]
1140 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1142 LPKEYSTRUCT lpxkey;
1143 int j;
1144 LPKEYVALUE valfrom;
1146 from=from->nextsub;
1147 while (from) {
1148 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1150 for (j=0;j<from->nrofvalues;j++) {
1151 LPWSTR name;
1152 LPBYTE data;
1154 valfrom = from->values+j;
1155 name=valfrom->name;
1156 if (name) name=strdupW(name);
1157 data=(LPBYTE)xmalloc(valfrom->len);
1158 memcpy(data,valfrom->data,valfrom->len);
1160 _find_or_add_value(
1161 lpxkey,
1162 name,
1163 valfrom->type,
1164 data,
1165 valfrom->len,
1166 valfrom->lastmodified
1169 _copy_registry(from,lpxkey);
1170 from = from->next;
1175 /* WINDOWS 95 REGISTRY LOADER */
1177 * Structure of a win95 registry database.
1178 * main header:
1179 * 0 : "CREG" - magic
1180 * 4 : DWORD version
1181 * 8 : DWORD offset_of_RGDB_part
1182 * 0C..0F: ? (someone fill in please)
1183 * 10: WORD number of RGDB blocks
1184 * 12: WORD ?
1185 * 14: WORD always 0000?
1186 * 16: WORD always 0001?
1187 * 18..1F: ? (someone fill in please)
1189 * 20: RGKN_section:
1190 * header:
1191 * 0 : "RGKN" - magic
1192 * 4 : DWORD offset to first RGDB section
1193 * 8 : DWORD offset to the root record
1194 * C..0x1B: ? (fill in)
1195 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1197 * Disk Key Entry Structure:
1198 * 00: DWORD - Free entry indicator(?)
1199 * 04: DWORD - Hash = sum of bytes of keyname
1200 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1201 * 0C: DWORD - disk address of PreviousLevel Key.
1202 * 10: DWORD - disk address of Next Sublevel Key.
1203 * 14: DWORD - disk address of Next Key (on same level).
1204 * DKEP>18: WORD - Nr, Low Significant part.
1205 * 1A: WORD - Nr, High Significant part.
1207 * The disk address always points to the nr part of the previous key entry
1208 * of the referenced key. Don't ask me why, or even if I got this correct
1209 * from staring at 1kg of hexdumps. (DKEP)
1211 * The High significant part of the structure seems to equal the number
1212 * of the RGDB section. The low significant part is a unique ID within
1213 * that RGDB section
1215 * There are two minor corrections to the position of that structure.
1216 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1217 * the DKE reread from there.
1218 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1219 * CPS - I have not experienced the above phenomenon in my registry files
1221 * RGDB_section:
1222 * 00: "RGDB" - magic
1223 * 04: DWORD offset to next RGDB section
1224 * 08: DWORD ?
1225 * 0C: WORD always 000d?
1226 * 0E: WORD RGDB block number
1227 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1228 * 14..1F: ?
1229 * 20.....: disk keys
1231 * disk key:
1232 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1233 * 08: WORD nrLS - low significant part of NR
1234 * 0A: WORD nrHS - high significant part of NR
1235 * 0C: DWORD bytesused - bytes used in this structure.
1236 * 10: WORD name_len - length of name in bytes. without \0
1237 * 12: WORD nr_of_values - number of values.
1238 * 14: char name[name_len] - name string. No \0.
1239 * 14+name_len: disk values
1240 * nextkeyoffset: ... next disk key
1242 * disk value:
1243 * 00: DWORD type - value type (hmm, could be WORD too)
1244 * 04: DWORD - unknown, usually 0
1245 * 08: WORD namelen - length of Name. 0 means name=NULL
1246 * 0C: WORD datalen - length of Data.
1247 * 10: char name[namelen] - name, no \0
1248 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1249 * 10+namelen+datalen: next values or disk key
1251 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1252 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1253 * structure) and reading another RGDB_section.
1254 * repeat until end of file.
1256 * An interesting relationship exists in RGDB_section. The value at offset
1257 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1258 * idea at the moment what this means. (Kevin Cozens)
1260 * FIXME: this description needs some serious help, yes.
1263 struct _w95keyvalue {
1264 unsigned long type;
1265 unsigned short datalen;
1266 char *name;
1267 unsigned char *data;
1268 unsigned long x1;
1269 int lastmodified;
1272 struct _w95key {
1273 char *name;
1274 int nrofvals;
1275 struct _w95keyvalue *values;
1276 struct _w95key *prevlvl;
1277 struct _w95key *nextsub;
1278 struct _w95key *next;
1282 struct _w95_info {
1283 char *rgknbuffer;
1284 int rgknsize;
1285 char *rgdbbuffer;
1286 int rgdbsize;
1287 int depth;
1288 int lastmodified;
1292 /******************************************************************************
1293 * _w95_processKey [Internal]
1295 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1296 int nrLS, int nrMS, struct _w95_info *info )
1299 /* Disk Key Header structure (RGDB part) */
1300 struct dkh {
1301 unsigned long nextkeyoff;
1302 unsigned short nrLS;
1303 unsigned short nrMS;
1304 unsigned long bytesused;
1305 unsigned short keynamelen;
1306 unsigned short values;
1307 unsigned long xx1;
1308 /* keyname */
1309 /* disk key values or nothing */
1311 /* Disk Key Value structure */
1312 struct dkv {
1313 unsigned long type;
1314 unsigned long x1;
1315 unsigned short valnamelen;
1316 unsigned short valdatalen;
1317 /* valname, valdata */
1321 struct dkh dkh;
1322 int bytesread = 0;
1323 char *rgdbdata = info->rgdbbuffer;
1324 int nbytes = info->rgdbsize;
1325 char *curdata = rgdbdata;
1326 char *end = rgdbdata + nbytes;
1327 int off_next_rgdb;
1328 char *next = rgdbdata;
1329 int nrgdb, i;
1330 LPKEYSTRUCT lpxkey;
1332 do {
1333 curdata = next;
1334 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1336 memcpy(&off_next_rgdb,curdata+4,4);
1337 next = curdata + off_next_rgdb;
1338 nrgdb = (int) *((short *)curdata + 7);
1340 } while (nrgdb != nrMS && (next < end));
1342 /* curdata now points to the start of the right RGDB section */
1343 curdata += 0x20;
1345 #define XREAD(whereto,len) \
1346 if ((curdata + len) <end) {\
1347 memcpy(whereto,curdata,len);\
1348 curdata+=len;\
1349 bytesread+=len;\
1352 while (curdata < next) {
1353 struct dkh *xdkh = (struct dkh*)curdata;
1355 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1356 if (xdkh->nrLS == nrLS) {
1357 memcpy(&dkh,xdkh,sizeof(dkh));
1358 curdata += sizeof(dkh);
1359 break;
1361 curdata += xdkh->nextkeyoff;
1364 if (dkh.nrLS != nrLS) return (NULL);
1366 if (nrgdb != dkh.nrMS)
1367 return (NULL);
1369 assert((dkh.keynamelen<2) || curdata[0]);
1370 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1371 curdata += dkh.keynamelen;
1373 for (i=0;i< dkh.values; i++) {
1374 struct dkv dkv;
1375 LPBYTE data;
1376 int len;
1377 LPWSTR name;
1379 XREAD(&dkv,sizeof(dkv));
1381 name = strcvtA2W(curdata, dkv.valnamelen);
1382 curdata += dkv.valnamelen;
1384 if ((1 << dkv.type) & UNICONVMASK) {
1385 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1386 len = 2*(dkv.valdatalen + 1);
1387 } else {
1388 /* I don't think we want to NULL terminate all data */
1389 data = xmalloc(dkv.valdatalen);
1390 memcpy (data, curdata, dkv.valdatalen);
1391 len = dkv.valdatalen;
1394 curdata += dkv.valdatalen;
1396 _find_or_add_value(
1397 lpxkey,
1398 name,
1399 dkv.type,
1400 data,
1401 len,
1402 info->lastmodified
1405 return (lpxkey);
1408 /******************************************************************************
1409 * _w95_walkrgkn [Internal]
1411 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1412 struct _w95_info *info )
1415 /* Disk Key Entry structure (RGKN part) */
1416 struct dke {
1417 unsigned long x1;
1418 unsigned long x2;
1419 unsigned long x3;/*usually 0xFFFFFFFF */
1420 unsigned long prevlvl;
1421 unsigned long nextsub;
1422 unsigned long next;
1423 unsigned short nrLS;
1424 unsigned short nrMS;
1425 } *dke = (struct dke *)off;
1426 LPKEYSTRUCT lpxkey;
1428 if (dke == NULL) {
1429 dke = (struct dke *) ((char *)info->rgknbuffer);
1432 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1433 /* XXX <-- This is a hack*/
1434 if (!lpxkey) {
1435 lpxkey = prevkey;
1438 if (dke->nextsub != -1 &&
1439 ((dke->nextsub - 0x20) < info->rgknsize)
1440 && (dke->nextsub > 0x20)) {
1442 _w95_walkrgkn(lpxkey,
1443 info->rgknbuffer + dke->nextsub - 0x20,
1444 info);
1447 if (dke->next != -1 &&
1448 ((dke->next - 0x20) < info->rgknsize) &&
1449 (dke->next > 0x20)) {
1450 _w95_walkrgkn(prevkey,
1451 info->rgknbuffer + dke->next - 0x20,
1452 info);
1455 return;
1459 /******************************************************************************
1460 * _w95_loadreg [Internal]
1462 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1464 HFILE hfd;
1465 char magic[5];
1466 unsigned long where,version,rgdbsection,end;
1467 struct _w95_info info;
1468 OFSTRUCT ofs;
1469 BY_HANDLE_FILE_INFORMATION hfdinfo;
1471 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1472 hfd=OpenFile(fn,&ofs,OF_READ);
1473 if (hfd==HFILE_ERROR)
1474 return;
1475 magic[4]=0;
1476 if (4!=_lread(hfd,magic,4))
1477 return;
1478 if (strcmp(magic,"CREG")) {
1479 WARN(reg,"%s is not a w95 registry.\n",fn);
1480 return;
1482 if (4!=_lread(hfd,&version,4))
1483 return;
1484 if (4!=_lread(hfd,&rgdbsection,4))
1485 return;
1486 if (-1==_llseek(hfd,0x20,SEEK_SET))
1487 return;
1488 if (4!=_lread(hfd,magic,4))
1489 return;
1490 if (strcmp(magic,"RGKN")) {
1491 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1492 return;
1495 /* STEP 1: Keylink structures */
1496 if (-1==_llseek(hfd,0x40,SEEK_SET))
1497 return;
1498 where = 0x40;
1499 end = rgdbsection;
1501 info.rgknsize = end - where;
1502 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1503 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1504 return;
1506 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1507 return;
1509 end = hfdinfo.nFileSizeLow;
1510 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1512 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1513 return;
1515 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1516 info.rgdbsize = end - rgdbsection;
1518 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1519 return;
1520 _lclose(hfd);
1522 _w95_walkrgkn(lpkey, NULL, &info);
1524 free (info.rgdbbuffer);
1525 free (info.rgknbuffer);
1529 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1532 reghack - windows 3.11 registry data format demo program.
1534 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1535 a combined hash table and tree description, and finally a text table.
1537 The header is obvious from the struct header. The taboff1 and taboff2
1538 fields are always 0x20, and their usage is unknown.
1540 The 8-byte entry table has various entry types.
1542 tabent[0] is a root index. The second word has the index of the root of
1543 the directory.
1544 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1545 the index of the key/value that has that hash. Data with the same
1546 hash value are on a circular list. The other three words in the
1547 hash entry are always zero.
1548 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1549 entry: dirent and keyent/valent. They are identified by context.
1550 tabent[freeidx] is the first free entry. The first word in a free entry
1551 is the index of the next free entry. The last has 0 as a link.
1552 The other three words in the free list are probably irrelevant.
1554 Entries in text table are preceeded by a word at offset-2. This word
1555 has the value (2*index)+1, where index is the referring keyent/valent
1556 entry in the table. I have no suggestion for the 2* and the +1.
1557 Following the word, there are N bytes of data, as per the keyent/valent
1558 entry length. The offset of the keyent/valent entry is from the start
1559 of the text table to the first data byte.
1561 This information is not available from Microsoft. The data format is
1562 deduced from the reg.dat file by me. Mistakes may
1563 have been made. I claim no rights and give no guarantees for this program.
1565 Tor Sjøwall, tor@sn.no
1568 /* reg.dat header format */
1569 struct _w31_header {
1570 char cookie[8]; /* 'SHCC3.10' */
1571 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1572 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1573 unsigned long tabcnt; /* number of entries in index table */
1574 unsigned long textoff; /* offset of text part */
1575 unsigned long textsize; /* byte size of text part */
1576 unsigned short hashsize; /* hash size */
1577 unsigned short freeidx; /* free index */
1580 /* generic format of table entries */
1581 struct _w31_tabent {
1582 unsigned short w0, w1, w2, w3;
1585 /* directory tabent: */
1586 struct _w31_dirent {
1587 unsigned short sibling_idx; /* table index of sibling dirent */
1588 unsigned short child_idx; /* table index of child dirent */
1589 unsigned short key_idx; /* table index of key keyent */
1590 unsigned short value_idx; /* table index of value valent */
1593 /* key tabent: */
1594 struct _w31_keyent {
1595 unsigned short hash_idx; /* hash chain index for string */
1596 unsigned short refcnt; /* reference count */
1597 unsigned short length; /* length of string */
1598 unsigned short string_off; /* offset of string in text table */
1601 /* value tabent: */
1602 struct _w31_valent {
1603 unsigned short hash_idx; /* hash chain index for string */
1604 unsigned short refcnt; /* reference count */
1605 unsigned short length; /* length of string */
1606 unsigned short string_off; /* offset of string in text table */
1609 /* recursive helper function to display a directory tree */
1610 void
1611 __w31_dumptree( unsigned short idx,
1612 unsigned char *txt,
1613 struct _w31_tabent *tab,
1614 struct _w31_header *head,
1615 LPKEYSTRUCT lpkey,
1616 time_t lastmodified,
1617 int level
1619 struct _w31_dirent *dir;
1620 struct _w31_keyent *key;
1621 struct _w31_valent *val;
1622 LPKEYSTRUCT xlpkey = NULL;
1623 LPWSTR name,value;
1624 static char tail[400];
1626 while (idx!=0) {
1627 dir=(struct _w31_dirent*)&tab[idx];
1629 if (dir->key_idx) {
1630 key = (struct _w31_keyent*)&tab[dir->key_idx];
1632 memcpy(tail,&txt[key->string_off],key->length);
1633 tail[key->length]='\0';
1634 /* all toplevel entries AND the entries in the
1635 * toplevel subdirectory belong to \SOFTWARE\Classes
1637 if (!level && !lstrcmpA(tail,".classes")) {
1638 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1639 idx=dir->sibling_idx;
1640 continue;
1642 name=strdupA2W(tail);
1644 xlpkey=_find_or_add_key(lpkey,name);
1646 /* only add if leaf node or valued node */
1647 if (dir->value_idx!=0||dir->child_idx==0) {
1648 if (dir->value_idx) {
1649 val=(struct _w31_valent*)&tab[dir->value_idx];
1650 memcpy(tail,&txt[val->string_off],val->length);
1651 tail[val->length]='\0';
1652 value=strdupA2W(tail);
1653 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1656 } else {
1657 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1659 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1660 idx=dir->sibling_idx;
1665 /******************************************************************************
1666 * _w31_loadreg [Internal]
1668 void _w31_loadreg(void) {
1669 HFILE hf;
1670 struct _w31_header head;
1671 struct _w31_tabent *tab;
1672 unsigned char *txt;
1673 int len;
1674 OFSTRUCT ofs;
1675 BY_HANDLE_FILE_INFORMATION hfinfo;
1676 time_t lastmodified;
1677 LPKEYSTRUCT lpkey;
1679 TRACE(reg,"(void)\n");
1681 hf = OpenFile("reg.dat",&ofs,OF_READ);
1682 if (hf==HFILE_ERROR)
1683 return;
1685 /* read & dump header */
1686 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1687 ERR(reg, "reg.dat is too short.\n");
1688 _lclose(hf);
1689 return;
1691 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1692 ERR(reg, "reg.dat has bad signature.\n");
1693 _lclose(hf);
1694 return;
1697 len = head.tabcnt * sizeof(struct _w31_tabent);
1698 /* read and dump index table */
1699 tab = xmalloc(len);
1700 if (len!=_lread(hf,tab,len)) {
1701 ERR(reg,"couldn't read %d bytes.\n",len);
1702 free(tab);
1703 _lclose(hf);
1704 return;
1707 /* read text */
1708 txt = xmalloc(head.textsize);
1709 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1710 ERR(reg,"couldn't seek to textblock.\n");
1711 free(tab);
1712 free(txt);
1713 _lclose(hf);
1714 return;
1716 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1717 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1718 free(tab);
1719 free(txt);
1720 _lclose(hf);
1721 return;
1724 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1725 ERR(reg,"GetFileInformationByHandle failed?.\n");
1726 free(tab);
1727 free(txt);
1728 _lclose(hf);
1729 return;
1731 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1732 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1733 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1734 free(tab);
1735 free(txt);
1736 _lclose(hf);
1737 return;
1741 /**********************************************************************************
1742 * SHELL_LoadRegistry [Internal]
1744 void SHELL_LoadRegistry( void )
1746 char *fn;
1747 struct passwd *pwd;
1748 LPKEYSTRUCT lpkey;
1749 HKEY hkey;
1751 TRACE(reg,"(void)\n");
1753 /* Load windows 3.1 entries */
1754 _w31_loadreg();
1755 /* Load windows 95 entries */
1756 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE));
1757 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE));
1758 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS));
1760 /* the global user default is loaded under HKEY_USERS\\.Default */
1761 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1762 lpkey = lookup_hkey(hkey);
1763 if(!lpkey)
1764 WARN(reg,"Could not create global user default key\n");
1765 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1767 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1768 _copy_registry(lpkey,lookup_hkey(HKEY_CURRENT_USER));
1769 RegCloseKey(hkey);
1771 /* the global machine defaults */
1772 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),SAVE_LOCAL_MACHINE_DEFAULT,0);
1774 /* load the user saved registries */
1776 /* Try to load config file specified files */
1778 fn = xmalloc( MAX_PATHNAME_LEN );
1779 if (PROFILE_GetWineIniString ("Registry", "UserFileName", "", fn, MAX_PATHNAME_LEN - 1)) {
1780 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,0);
1782 free (fn);
1784 fn = xmalloc ( MAX_PATHNAME_LEN);
1785 if (PROFILE_GetWineIniString ("Registry", "LocalMachineFileName", "", fn, MAX_PATHNAME_LEN - 1)){
1786 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, 0);
1788 free (fn);
1790 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1791 /* FIXME: user's home/.wine/user.reg and system.reg files are not
1792 blocked from loading not sure if we want to or not.*/
1795 pwd=getpwuid(getuid());
1796 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1797 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1798 strcpy(fn,pwd->pw_dir);
1799 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1800 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,REG_OPTION_TAINTED);
1801 free(fn);
1802 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1803 strcpy(fn,pwd->pw_dir);
1804 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1805 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),fn,REG_OPTION_TAINTED);
1806 free(fn);
1807 } else
1808 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1809 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1810 DWORD junk,type,len;
1811 char data[5];
1813 len=4;
1814 if (( RegQueryValueExA(
1815 hkey,
1816 VAL_SAVEUPDATED,
1817 &junk,
1818 &type,
1819 data,
1820 &len
1821 )!=ERROR_SUCCESS) ||
1822 type != REG_SZ
1824 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1825 RegCloseKey(hkey);
1830 /********************* API FUNCTIONS ***************************************/
1832 * Open Keys.
1834 * All functions are stubs to RegOpenKeyEx32W where all the
1835 * magic happens.
1837 * Callpath:
1838 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1839 * RegOpenKey32W -> RegOpenKeyEx32W
1843 /******************************************************************************
1844 * RegOpenKeyEx32W [ADVAPI32.150]
1845 * Opens the specified key
1847 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1849 * PARAMS
1850 * hkey [I] Handle of open key
1851 * lpszSubKey [I] Name of subkey to open
1852 * dwReserved [I] Reserved - must be zero
1853 * samDesired [I] Security access mask
1854 * retkey [O] Address of handle of open key
1856 * RETURNS
1857 * Success: ERROR_SUCCESS
1858 * Failure: Error code
1860 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
1861 REGSAM samDesired, LPHKEY retkey )
1863 LPKEYSTRUCT lpNextKey,lpxkey;
1864 LPWSTR *wps;
1865 int wpc,i;
1867 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1868 samDesired,retkey);
1870 lpNextKey = lookup_hkey( hkey );
1871 if (!lpNextKey)
1872 return ERROR_INVALID_HANDLE;
1874 if (!lpszSubKey || !*lpszSubKey) {
1875 /* Either NULL or pointer to empty string, so return a new handle
1876 to the original hkey */
1877 currenthandle += 2;
1878 add_handle(currenthandle,lpNextKey,samDesired);
1879 *retkey=currenthandle;
1880 return ERROR_SUCCESS;
1883 if (lpszSubKey[0] == '\\') {
1884 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1885 return ERROR_BAD_PATHNAME;
1888 split_keypath(lpszSubKey,&wps,&wpc);
1889 i = 0;
1890 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1891 lpxkey = lpNextKey;
1893 while (wps[i]) {
1894 lpxkey=lpNextKey->nextsub;
1895 while (lpxkey) {
1896 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
1897 break;
1899 lpxkey=lpxkey->next;
1902 if (!lpxkey) {
1903 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1904 FREE_KEY_PATH;
1905 return ERROR_FILE_NOT_FOUND;
1907 i++;
1908 lpNextKey = lpxkey;
1911 currenthandle += 2;
1912 add_handle(currenthandle,lpxkey,samDesired);
1913 *retkey = currenthandle;
1914 TRACE(reg," Returning %x\n", currenthandle);
1915 FREE_KEY_PATH;
1916 return ERROR_SUCCESS;
1920 /******************************************************************************
1921 * RegOpenKeyEx32A [ADVAPI32.149]
1923 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1924 REGSAM samDesired, LPHKEY retkey )
1926 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1927 DWORD ret;
1929 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1930 samDesired,retkey);
1931 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
1932 free(lpszSubKeyW);
1933 return ret;
1937 /******************************************************************************
1938 * RegOpenKey32W [ADVAPI32.151]
1940 * PARAMS
1941 * hkey [I] Handle of open key
1942 * lpszSubKey [I] Address of name of subkey to open
1943 * retkey [O] Address of handle of open key
1945 * RETURNS
1946 * Success: ERROR_SUCCESS
1947 * Failure: Error code
1949 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1951 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
1952 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1956 /******************************************************************************
1957 * RegOpenKey32A [ADVAPI32.148]
1959 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1961 DWORD ret;
1962 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1963 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1964 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
1965 free(lpszSubKeyW);
1966 return ret;
1970 /******************************************************************************
1971 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1973 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1975 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1976 return RegOpenKeyA( hkey, lpszSubKey, retkey );
1981 * Create keys
1983 * All those functions convert their respective
1984 * arguments and call RegCreateKeyExW at the end.
1986 * We stay away from the Ex functions as long as possible because there are
1987 * differences in the return values
1989 * Callpath:
1990 * RegCreateKeyEx32A \
1991 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1995 /******************************************************************************
1996 * RegCreateKeyEx32W [ADVAPI32.131]
1998 * PARAMS
1999 * hkey [I] Handle of an open key
2000 * lpszSubKey [I] Address of subkey name
2001 * dwReserved [I] Reserved - must be 0
2002 * lpszClass [I] Address of class string
2003 * fdwOptions [I] Special options flag
2004 * samDesired [I] Desired security access
2005 * lpSecAttribs [I] Address of key security structure
2006 * retkey [O] Address of buffer for opened handle
2007 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2009 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2010 DWORD dwReserved, LPWSTR lpszClass,
2011 DWORD fdwOptions, REGSAM samDesired,
2012 LPSECURITY_ATTRIBUTES lpSecAttribs,
2013 LPHKEY retkey, LPDWORD lpDispos )
2015 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2016 LPWSTR *wps;
2017 int wpc,i;
2019 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2020 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2021 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2023 lpNextKey = lookup_hkey(hkey);
2024 if (!lpNextKey)
2025 return ERROR_INVALID_HANDLE;
2027 /* Check for valid options */
2028 switch(fdwOptions) {
2029 case REG_OPTION_NON_VOLATILE:
2030 case REG_OPTION_VOLATILE:
2031 case REG_OPTION_BACKUP_RESTORE:
2032 break;
2033 default:
2034 return ERROR_INVALID_PARAMETER;
2037 /* Sam has to be a combination of the following */
2038 if (!(samDesired &
2039 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2040 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2041 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2042 return ERROR_INVALID_PARAMETER;
2044 if (!lpszSubKey || !*lpszSubKey) {
2045 currenthandle += 2;
2046 add_handle(currenthandle,lpNextKey,samDesired);
2047 *retkey=currenthandle;
2048 TRACE(reg, "Returning %x\n", currenthandle);
2049 lpNextKey->flags|=REG_OPTION_TAINTED;
2050 return ERROR_SUCCESS;
2053 if (lpszSubKey[0] == '\\') {
2054 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2055 return ERROR_BAD_PATHNAME;
2058 split_keypath(lpszSubKey,&wps,&wpc);
2059 i = 0;
2060 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2061 lpxkey = lpNextKey;
2062 while (wps[i]) {
2063 lpxkey=lpNextKey->nextsub;
2064 while (lpxkey) {
2065 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2066 break;
2067 lpxkey=lpxkey->next;
2069 if (!lpxkey)
2070 break;
2071 i++;
2072 lpNextKey = lpxkey;
2074 if (lpxkey) {
2075 currenthandle += 2;
2076 add_handle(currenthandle,lpxkey,samDesired);
2077 lpxkey->flags |= REG_OPTION_TAINTED;
2078 *retkey = currenthandle;
2079 TRACE(reg, "Returning %x\n", currenthandle);
2080 if (lpDispos)
2081 *lpDispos = REG_OPENED_EXISTING_KEY;
2082 FREE_KEY_PATH;
2083 return ERROR_SUCCESS;
2086 /* Good. Now the hard part */
2087 while (wps[i]) {
2088 lplpPrevKey = &(lpNextKey->nextsub);
2089 lpxkey = *lplpPrevKey;
2090 while (lpxkey) {
2091 lplpPrevKey = &(lpxkey->next);
2092 lpxkey = *lplpPrevKey;
2094 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2095 if (!*lplpPrevKey) {
2096 FREE_KEY_PATH;
2097 TRACE(reg, "Returning OUTOFMEMORY\n");
2098 return ERROR_OUTOFMEMORY;
2100 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2101 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2102 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2103 (*lplpPrevKey)->next = NULL;
2104 (*lplpPrevKey)->nextsub = NULL;
2105 (*lplpPrevKey)->values = NULL;
2106 (*lplpPrevKey)->nrofvalues = 0;
2107 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2108 if (lpszClass)
2109 (*lplpPrevKey)->class = strdupW(lpszClass);
2110 else
2111 (*lplpPrevKey)->class = NULL;
2112 lpNextKey = *lplpPrevKey;
2113 i++;
2115 currenthandle += 2;
2116 add_handle(currenthandle,lpNextKey,samDesired);
2118 /*FIXME: flag handling correct? */
2119 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2120 if (lpszClass)
2121 lpNextKey->class = strdupW(lpszClass);
2122 else
2123 lpNextKey->class = NULL;
2124 *retkey = currenthandle;
2125 TRACE(reg, "Returning %x\n", currenthandle);
2126 if (lpDispos)
2127 *lpDispos = REG_CREATED_NEW_KEY;
2128 FREE_KEY_PATH;
2129 return ERROR_SUCCESS;
2133 /******************************************************************************
2134 * RegCreateKeyEx32A [ADVAPI32.130]
2136 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2137 LPSTR lpszClass, DWORD fdwOptions,
2138 REGSAM samDesired,
2139 LPSECURITY_ATTRIBUTES lpSecAttribs,
2140 LPHKEY retkey, LPDWORD lpDispos )
2142 LPWSTR lpszSubKeyW, lpszClassW;
2143 DWORD ret;
2145 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2146 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2147 retkey,lpDispos);
2149 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2150 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2152 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2153 fdwOptions, samDesired, lpSecAttribs, retkey,
2154 lpDispos );
2156 if(lpszSubKeyW) free(lpszSubKeyW);
2157 if(lpszClassW) free(lpszClassW);
2159 return ret;
2163 /******************************************************************************
2164 * RegCreateKey32W [ADVAPI32.132]
2166 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2168 DWORD junk;
2169 LPKEYSTRUCT lpNextKey;
2171 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2173 /* This check is here because the return value is different than the
2174 one from the Ex functions */
2175 lpNextKey = lookup_hkey(hkey);
2176 if (!lpNextKey)
2177 return ERROR_BADKEY;
2179 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2180 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2181 retkey, &junk);
2185 /******************************************************************************
2186 * RegCreateKey32A [ADVAPI32.129]
2188 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2190 DWORD ret;
2191 LPWSTR lpszSubKeyW;
2193 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2194 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2195 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2196 if(lpszSubKeyW) free(lpszSubKeyW);
2197 return ret;
2201 /******************************************************************************
2202 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2204 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2206 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2207 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2212 * Query Value Functions
2213 * Win32 differs between keynames and valuenames.
2214 * multiple values may belong to one key, the special value
2215 * with name NULL is the default value used by the win31
2216 * compat functions.
2218 * Callpath:
2219 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2220 * RegQueryValue32W -> RegQueryValueEx32W
2224 /******************************************************************************
2225 * RegQueryValueEx32W [ADVAPI32.158]
2226 * Retrieves type and data for a specified name associated with an open key
2228 * PARAMS
2229 * hkey [I] Handle of key to query
2230 * lpValueName [I] Name of value to query
2231 * lpdwReserved [I] Reserved - must be NULL
2232 * lpdwType [O] Address of buffer for value type. If NULL, the type
2233 * is not required.
2234 * lpbData [O] Address of data buffer. If NULL, the actual data is
2235 * not required.
2236 * lpcbData [I/O] Address of data buffer size
2238 * RETURNS
2239 * ERROR_SUCCESS: Success
2240 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2241 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2243 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPWSTR lpValueName,
2244 LPDWORD lpdwReserved, LPDWORD lpdwType,
2245 LPBYTE lpbData, LPDWORD lpcbData )
2247 LPKEYSTRUCT lpkey;
2248 int i;
2249 DWORD ret;
2251 TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2252 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2254 lpkey = lookup_hkey(hkey);
2256 if (!lpkey)
2257 return ERROR_INVALID_HANDLE;
2259 if ((lpbData && ! lpcbData) || lpdwReserved)
2260 return ERROR_INVALID_PARAMETER;
2262 /* An empty name string is equivalent to NULL */
2263 if (lpValueName && !*lpValueName)
2264 lpValueName = NULL;
2266 if (lpValueName==NULL)
2267 { /* Use key's unnamed or default value, if any */
2268 for (i=0;i<lpkey->nrofvalues;i++)
2269 if (lpkey->values[i].name==NULL)
2270 break;
2272 else
2273 { /* Search for the key name */
2274 for (i=0;i<lpkey->nrofvalues;i++)
2275 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2276 break;
2279 if (i==lpkey->nrofvalues)
2280 { TRACE(reg," Key not found\n");
2281 if (lpValueName==NULL)
2282 { /* Empty keyname not found */
2283 if (lpbData)
2284 { *(WCHAR*)lpbData = 0;
2285 *lpcbData = 2;
2287 if (lpdwType)
2288 *lpdwType = REG_SZ;
2289 TRACE(reg, " Returning an empty string\n");
2290 return ERROR_SUCCESS;
2292 return ERROR_FILE_NOT_FOUND;
2295 ret = ERROR_SUCCESS;
2297 if (lpdwType) /* type required ?*/
2298 *lpdwType = lpkey->values[i].type;
2300 if (lpbData) /* data required ?*/
2301 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2302 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2303 else
2304 ret = ERROR_MORE_DATA;
2307 if (lpcbData) /* size required ?*/
2308 { *lpcbData = lpkey->values[i].len;
2311 debug_print_value ( lpbData, lpkey->values[i].type, lpkey->values[i].len);
2313 TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2315 return ret;
2319 /******************************************************************************
2320 * RegQueryValue32W [ADVAPI32.159]
2322 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2323 LPLONG lpcbData )
2325 HKEY xhkey;
2326 DWORD ret,lpdwType;
2328 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2329 lpcbData?*lpcbData:0);
2331 /* Only open subkey, if we really do descend */
2332 if (lpszSubKey && *lpszSubKey) {
2333 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2334 if (ret != ERROR_SUCCESS) {
2335 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2336 return ret;
2338 } else
2339 xhkey = hkey;
2341 lpdwType = REG_SZ;
2342 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2343 lpcbData );
2344 if (xhkey != hkey)
2345 RegCloseKey(xhkey);
2346 return ret;
2350 /******************************************************************************
2351 * RegQueryValueEx32A [ADVAPI32.157]
2353 * NOTES:
2354 * the documantation is wrong: if the buffer is to small it remains untouched
2356 * FIXME: check returnvalue (len) for an empty key
2358 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPSTR lpszValueName,
2359 LPDWORD lpdwReserved, LPDWORD lpdwType,
2360 LPBYTE lpbData, LPDWORD lpcbData )
2362 LPWSTR lpszValueNameW;
2363 LPBYTE mybuf = NULL;
2364 DWORD ret, mytype, mylen = 0;
2366 TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2367 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2369 if (!lpcbData && lpbData) /* buffer without size is illegal */
2370 { return ERROR_INVALID_PARAMETER;
2373 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2375 /* get just the type first */
2376 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2378 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2379 { if(lpszValueNameW) free(lpszValueNameW);
2380 return ret;
2383 if (lpcbData) /* at least length requested? */
2384 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2385 { if (lpbData ) /* value requested? */
2386 { mylen = 2*( *lpcbData );
2387 mybuf = (LPBYTE)xmalloc( mylen );
2390 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2392 if (ret == ERROR_SUCCESS )
2393 { if ( lpbData )
2394 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2398 *lpcbData = mylen/2; /* size is in byte! */
2400 else /* no strings, call it straight */
2401 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2405 if (lpdwType) /* type when requested */
2406 { *lpdwType = mytype;
2409 TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2411 if(mybuf) free(mybuf);
2412 if(lpszValueNameW) free(lpszValueNameW);
2413 return ret;
2417 /******************************************************************************
2418 * RegQueryValueEx16 [KERNEL.225]
2420 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2421 LPDWORD lpdwReserved, LPDWORD lpdwType,
2422 LPBYTE lpbData, LPDWORD lpcbData )
2424 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2425 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2426 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2427 lpbData, lpcbData );
2431 /******************************************************************************
2432 * RegQueryValue32A [ADVAPI32.156]
2434 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2435 LPLONG lpcbData )
2437 HKEY xhkey;
2438 DWORD ret, dwType;
2440 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2441 lpcbData?*lpcbData:0);
2443 if (lpszSubKey && *lpszSubKey) {
2444 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2445 if( ret != ERROR_SUCCESS )
2446 return ret;
2447 } else
2448 xhkey = hkey;
2450 dwType = REG_SZ;
2451 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2452 lpcbData );
2453 if( xhkey != hkey )
2454 RegCloseKey( xhkey );
2455 return ret;
2459 /******************************************************************************
2460 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2462 * NOTES
2463 * Is this HACK still applicable?
2465 * HACK
2466 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2467 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2468 * Aldus FH4)
2470 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2471 LPDWORD lpcbData )
2473 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2474 lpcbData?*lpcbData:0);
2476 if (lpcbData)
2477 *lpcbData &= 0xFFFF;
2478 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2483 * Setting values of Registry keys
2485 * Callpath:
2486 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2487 * RegSetValue32W -> RegSetValueEx32W
2491 /******************************************************************************
2492 * RegSetValueEx32W [ADVAPI32.170]
2493 * Sets the data and type of a value under a register key
2495 * PARAMS
2496 * hkey [I] Handle of key to set value for
2497 * lpszValueName [I] Name of value to set
2498 * dwReserved [I] Reserved - must be zero
2499 * dwType [I] Flag for value type
2500 * lpbData [I] Address of value data
2501 * cbData [I] Size of value data
2503 * RETURNS
2504 * Success: ERROR_SUCCESS
2505 * Failure: Error code
2507 * NOTES
2508 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2510 DWORD WINAPI RegSetValueExW( HKEY hkey, LPWSTR lpszValueName,
2511 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2512 DWORD cbData)
2514 LPKEYSTRUCT lpkey;
2515 int i;
2517 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2518 dwReserved, dwType, lpbData, cbData);
2520 debug_print_value ( lpbData, dwType, cbData );
2522 lpkey = lookup_hkey( hkey );
2524 if (!lpkey)
2525 return ERROR_INVALID_HANDLE;
2527 lpkey->flags |= REG_OPTION_TAINTED;
2529 if (lpszValueName==NULL) {
2530 /* Sets type and name for key's unnamed or default value */
2531 for (i=0;i<lpkey->nrofvalues;i++)
2532 if (lpkey->values[i].name==NULL)
2533 break;
2534 } else {
2535 for (i=0;i<lpkey->nrofvalues;i++)
2536 if ( lpkey->values[i].name &&
2537 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2539 break;
2541 if (i==lpkey->nrofvalues) {
2542 lpkey->values = (LPKEYVALUE)xrealloc(
2543 lpkey->values,
2544 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2546 lpkey->nrofvalues++;
2547 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2549 if (lpkey->values[i].name==NULL) {
2550 if (lpszValueName)
2551 lpkey->values[i].name = strdupW(lpszValueName);
2552 else
2553 lpkey->values[i].name = NULL;
2556 if (dwType == REG_SZ)
2557 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2559 lpkey->values[i].len = cbData;
2560 lpkey->values[i].type = dwType;
2561 if (lpkey->values[i].data !=NULL)
2562 free(lpkey->values[i].data);
2563 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2564 lpkey->values[i].lastmodified = time(NULL);
2565 memcpy(lpkey->values[i].data,lpbData,cbData);
2566 return ERROR_SUCCESS;
2570 /******************************************************************************
2571 * RegSetValueEx32A [ADVAPI32.169]
2573 * NOTES
2574 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2576 DWORD WINAPI RegSetValueExA( HKEY hkey, LPSTR lpszValueName,
2577 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2578 DWORD cbData )
2580 LPBYTE buf;
2581 LPWSTR lpszValueNameW;
2582 DWORD ret;
2584 if (!lpbData)
2585 return (ERROR_INVALID_PARAMETER);
2587 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2588 dwReserved,dwType,lpbData,cbData);
2590 if ((1<<dwType) & UNICONVMASK)
2591 { if (dwType == REG_SZ)
2592 cbData = strlen ((LPCSTR)lpbData)+1;
2594 buf = (LPBYTE)xmalloc( cbData *2 );
2595 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2596 cbData=2*cbData;
2598 else
2599 buf=lpbData;
2601 if (lpszValueName)
2602 lpszValueNameW = strdupA2W(lpszValueName);
2603 else
2604 lpszValueNameW = NULL;
2606 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2608 if (lpszValueNameW)
2609 free(lpszValueNameW);
2611 if (buf!=lpbData)
2612 free(buf);
2614 return ret;
2618 /******************************************************************************
2619 * RegSetValueEx16 [KERNEL.226]
2621 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2622 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2624 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2625 dwReserved,dwType,lpbData,cbData);
2626 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2627 cbData );
2631 /******************************************************************************
2632 * RegSetValue32W [ADVAPI32.171]
2634 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2635 LPCWSTR lpszData, DWORD cbData )
2637 HKEY xhkey;
2638 DWORD ret;
2640 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2641 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2643 if (lpszSubKey && *lpszSubKey) {
2644 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2645 if (ret!=ERROR_SUCCESS)
2646 return ret;
2647 } else
2648 xhkey=hkey;
2649 if (dwType!=REG_SZ) {
2650 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2651 dwType=REG_SZ;
2653 if (cbData!=2*lstrlenW(lpszData)+2) {
2654 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2655 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2657 cbData=2*lstrlenW(lpszData)+2;
2659 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2660 if (hkey!=xhkey)
2661 RegCloseKey(xhkey);
2662 return ret;
2666 /******************************************************************************
2667 * RegSetValue32A [ADVAPI32.168]
2670 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2671 LPCSTR lpszData, DWORD cbData )
2673 DWORD ret;
2674 HKEY xhkey;
2676 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2677 if (lpszSubKey && *lpszSubKey) {
2678 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2679 if (ret!=ERROR_SUCCESS)
2680 return ret;
2681 } else
2682 xhkey=hkey;
2684 if (dwType!=REG_SZ) {
2685 TRACE(reg,"dwType=%ld!\n",dwType);
2686 dwType=REG_SZ;
2688 if (cbData!=strlen(lpszData)+1)
2689 cbData=strlen(lpszData)+1;
2690 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2691 if (xhkey!=hkey)
2692 RegCloseKey(xhkey);
2693 return ret;
2697 /******************************************************************************
2698 * RegSetValue16 [KERNEL.221] [SHELL.5]
2700 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2701 LPCSTR lpszData, DWORD cbData )
2703 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2704 debugstr_a(lpszData),cbData);
2705 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2710 * Key Enumeration
2712 * Callpath:
2713 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2714 * RegEnumKey32W -> RegEnumKeyEx32W
2718 /******************************************************************************
2719 * RegEnumKeyEx32W [ADVAPI32.139]
2721 * PARAMS
2722 * hkey [I] Handle to key to enumerate
2723 * iSubKey [I] Index of subkey to enumerate
2724 * lpszName [O] Buffer for subkey name
2725 * lpcchName [O] Size of subkey buffer
2726 * lpdwReserved [I] Reserved
2727 * lpszClass [O] Buffer for class string
2728 * lpcchClass [O] Size of class buffer
2729 * ft [O] Time key last written to
2731 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2732 LPDWORD lpcchName, LPDWORD lpdwReserved,
2733 LPWSTR lpszClass, LPDWORD lpcchClass,
2734 FILETIME *ft )
2736 LPKEYSTRUCT lpkey,lpxkey;
2738 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2739 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2741 lpkey = lookup_hkey( hkey );
2742 if (!lpkey)
2743 return ERROR_INVALID_HANDLE;
2745 if (!lpkey->nextsub)
2746 return ERROR_NO_MORE_ITEMS;
2747 lpxkey=lpkey->nextsub;
2749 /* Traverse the subkeys */
2750 while (iSubkey && lpxkey) {
2751 iSubkey--;
2752 lpxkey=lpxkey->next;
2755 if (iSubkey || !lpxkey)
2756 return ERROR_NO_MORE_ITEMS;
2757 if (lstrlenW(lpxkey->keyname)+1>*lpcchName)
2758 return ERROR_MORE_DATA;
2759 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
2761 if (*lpcchName)
2762 *lpcchName = lstrlenW(lpszName);
2764 if (lpszClass) {
2765 /* FIXME: what should we write into it? */
2766 *lpszClass = 0;
2767 *lpcchClass = 2;
2769 return ERROR_SUCCESS;
2773 /******************************************************************************
2774 * RegEnumKey32W [ADVAPI32.140]
2776 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2777 DWORD lpcchName )
2779 FILETIME ft;
2781 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2782 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2786 /******************************************************************************
2787 * RegEnumKeyEx32A [ADVAPI32.138]
2789 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2790 LPDWORD lpcchName, LPDWORD lpdwReserved,
2791 LPSTR lpszClass, LPDWORD lpcchClass,
2792 FILETIME *ft )
2794 DWORD ret,lpcchNameW,lpcchClassW;
2795 LPWSTR lpszNameW,lpszClassW;
2798 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2799 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2801 if (lpszName) {
2802 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2803 lpcchNameW = *lpcchName;
2804 } else {
2805 lpszNameW = NULL;
2806 lpcchNameW = 0;
2808 if (lpszClass) {
2809 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2810 lpcchClassW = *lpcchClass;
2811 } else {
2812 lpszClassW =0;
2813 lpcchClassW=0;
2815 ret=RegEnumKeyExW(
2816 hkey,
2817 iSubkey,
2818 lpszNameW,
2819 &lpcchNameW,
2820 lpdwReserved,
2821 lpszClassW,
2822 &lpcchClassW,
2825 if (ret==ERROR_SUCCESS) {
2826 lstrcpyWtoA(lpszName,lpszNameW);
2827 *lpcchName=strlen(lpszName);
2828 if (lpszClassW) {
2829 lstrcpyWtoA(lpszClass,lpszClassW);
2830 *lpcchClass=strlen(lpszClass);
2833 if (lpszNameW)
2834 free(lpszNameW);
2835 if (lpszClassW)
2836 free(lpszClassW);
2837 return ret;
2841 /******************************************************************************
2842 * RegEnumKey32A [ADVAPI32.137]
2844 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2845 DWORD lpcchName )
2847 FILETIME ft;
2849 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2850 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
2851 NULL, &ft );
2855 /******************************************************************************
2856 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2858 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2859 DWORD lpcchName )
2861 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2862 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
2867 * Enumerate Registry Values
2869 * Callpath:
2870 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2874 /******************************************************************************
2875 * RegEnumValue32W [ADVAPI32.142]
2877 * PARAMS
2878 * hkey [I] Handle to key to query
2879 * iValue [I] Index of value to query
2880 * lpszValue [O] Value string
2881 * lpcchValue [I/O] Size of value buffer (in wchars)
2882 * lpdReserved [I] Reserved
2883 * lpdwType [O] Type code
2884 * lpbData [O] Value data
2885 * lpcbData [I/O] Size of data buffer (in bytes)
2887 * Note: wide character functions that take and/or return "character counts"
2888 * use TCHAR (that is unsigned short or char) not byte counts.
2890 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
2891 LPDWORD lpcchValue, LPDWORD lpdReserved,
2892 LPDWORD lpdwType, LPBYTE lpbData,
2893 LPDWORD lpcbData )
2895 LPKEYSTRUCT lpkey;
2896 LPKEYVALUE val;
2898 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
2899 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
2901 lpkey = lookup_hkey( hkey );
2903 if (!lpcbData && lpbData)
2904 return ERROR_INVALID_PARAMETER;
2906 if (!lpkey)
2907 return ERROR_INVALID_HANDLE;
2909 if (lpkey->nrofvalues <= iValue)
2910 return ERROR_NO_MORE_ITEMS;
2912 val = &(lpkey->values[iValue]);
2914 if (val->name) {
2915 if (lstrlenW(val->name)+1>*lpcchValue) {
2916 *lpcchValue = lstrlenW(val->name)+1;
2917 return ERROR_MORE_DATA;
2919 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
2920 *lpcchValue=lstrlenW(val->name);
2921 } else {
2922 *lpszValue = 0;
2923 *lpcchValue = 0;
2926 /* Can be NULL if the type code is not required */
2927 if (lpdwType)
2928 *lpdwType = val->type;
2930 if (lpbData) {
2931 if (val->len>*lpcbData)
2932 return ERROR_MORE_DATA;
2933 memcpy(lpbData,val->data,val->len);
2934 *lpcbData = val->len;
2937 debug_print_value ( val->data, val->type, val->len );
2938 return ERROR_SUCCESS;
2942 /******************************************************************************
2943 * RegEnumValue32A [ADVAPI32.141]
2945 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2946 LPDWORD lpcchValue, LPDWORD lpdReserved,
2947 LPDWORD lpdwType, LPBYTE lpbData,
2948 LPDWORD lpcbData )
2950 LPWSTR lpszValueW;
2951 LPBYTE lpbDataW;
2952 DWORD ret,lpcbDataW;
2953 DWORD dwType;
2955 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2956 lpdReserved,lpdwType,lpbData,lpcbData);
2958 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2959 if (lpbData) {
2960 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2961 lpcbDataW = *lpcbData;
2962 } else
2963 lpbDataW = NULL;
2965 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
2966 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2968 if (lpdwType)
2969 *lpdwType = dwType;
2971 if (ret==ERROR_SUCCESS) {
2972 lstrcpyWtoA(lpszValue,lpszValueW);
2973 if (lpbData) {
2974 if ((1<<dwType) & UNICONVMASK) {
2975 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2976 } else {
2977 if (lpcbDataW > *lpcbData)
2978 ret = ERROR_MORE_DATA;
2979 else
2980 memcpy(lpbData,lpbDataW,lpcbDataW);
2982 *lpcbData = lpcbDataW;
2985 if (lpbDataW) free(lpbDataW);
2986 if (lpszValueW) free(lpszValueW);
2987 return ret;
2991 /******************************************************************************
2992 * RegEnumValue16 [KERNEL.223]
2994 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2995 LPDWORD lpcchValue, LPDWORD lpdReserved,
2996 LPDWORD lpdwType, LPBYTE lpbData,
2997 LPDWORD lpcbData )
2999 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3000 lpdReserved,lpdwType,lpbData,lpcbData);
3001 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3002 lpdwType, lpbData, lpcbData );
3006 /******************************************************************************
3007 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3008 * Releases the handle of the specified key
3010 * PARAMS
3011 * hkey [I] Handle of key to close
3013 * RETURNS
3014 * Success: ERROR_SUCCESS
3015 * Failure: Error code
3017 DWORD WINAPI RegCloseKey( HKEY hkey )
3019 TRACE(reg,"(%x)\n",hkey);
3021 /* The standard handles are allowed to succeed, even though they are not
3022 closed */
3023 if (is_standard_hkey(hkey))
3024 return ERROR_SUCCESS;
3026 return remove_handle(hkey);
3031 * Delete registry key
3033 * Callpath:
3034 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3038 /******************************************************************************
3039 * RegDeleteKey32W [ADVAPI32.134]
3041 * PARAMS
3042 * hkey [I] Handle to open key
3043 * lpszSubKey [I] Name of subkey to delete
3045 * RETURNS
3046 * Success: ERROR_SUCCESS
3047 * Failure: Error code
3049 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPWSTR lpszSubKey )
3051 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3052 LPWSTR *wps;
3053 int wpc,i;
3055 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3057 lpNextKey = lookup_hkey(hkey);
3058 if (!lpNextKey)
3059 return ERROR_INVALID_HANDLE;
3061 /* Subkey param cannot be NULL */
3062 if (!lpszSubKey || !*lpszSubKey)
3063 return ERROR_BADKEY;
3065 /* We need to know the previous key in the hier. */
3066 split_keypath(lpszSubKey,&wps,&wpc);
3067 i = 0;
3068 lpxkey = lpNextKey;
3069 while (i<wpc-1) {
3070 lpxkey=lpNextKey->nextsub;
3071 while (lpxkey) {
3072 TRACE(reg, " Scanning [%s]\n",
3073 debugstr_w(lpxkey->keyname));
3074 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3075 break;
3076 lpxkey=lpxkey->next;
3078 if (!lpxkey) {
3079 FREE_KEY_PATH;
3080 TRACE(reg, " Not found.\n");
3081 /* not found is success */
3082 return ERROR_SUCCESS;
3084 i++;
3085 lpNextKey = lpxkey;
3087 lpxkey = lpNextKey->nextsub;
3088 lplpPrevKey = &(lpNextKey->nextsub);
3089 while (lpxkey) {
3090 TRACE(reg, " Scanning [%s]\n",
3091 debugstr_w(lpxkey->keyname));
3092 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3093 break;
3094 lplpPrevKey = &(lpxkey->next);
3095 lpxkey = lpxkey->next;
3098 if (!lpxkey) {
3099 FREE_KEY_PATH;
3100 WARN(reg , " Not found.\n");
3101 return ERROR_FILE_NOT_FOUND;
3104 if (lpxkey->nextsub) {
3105 FREE_KEY_PATH;
3106 WARN(reg , " Not empty.\n");
3107 return ERROR_CANTWRITE;
3109 *lplpPrevKey = lpxkey->next;
3110 free(lpxkey->keyname);
3111 if (lpxkey->class)
3112 free(lpxkey->class);
3113 if (lpxkey->values)
3114 free(lpxkey->values);
3115 free(lpxkey);
3116 FREE_KEY_PATH;
3117 TRACE(reg, " Done.\n");
3118 return ERROR_SUCCESS;
3122 /******************************************************************************
3123 * RegDeleteKey32A [ADVAPI32.133]
3125 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3127 LPWSTR lpszSubKeyW;
3128 DWORD ret;
3130 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3131 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3132 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3133 if(lpszSubKeyW) free(lpszSubKeyW);
3134 return ret;
3138 /******************************************************************************
3139 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3141 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3143 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3144 return RegDeleteKeyA( hkey, lpszSubKey );
3149 * Delete registry value
3151 * Callpath:
3152 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3156 /******************************************************************************
3157 * RegDeleteValue32W [ADVAPI32.136]
3159 * PARAMS
3160 * hkey [I]
3161 * lpszValue [I]
3163 * RETURNS
3165 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPWSTR lpszValue )
3167 DWORD i;
3168 LPKEYSTRUCT lpkey;
3169 LPKEYVALUE val;
3171 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3173 lpkey = lookup_hkey( hkey );
3174 if (!lpkey)
3175 return ERROR_INVALID_HANDLE;
3177 if (lpszValue) {
3178 for (i=0;i<lpkey->nrofvalues;i++)
3179 if ( lpkey->values[i].name &&
3180 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3182 break;
3183 } else {
3184 for (i=0;i<lpkey->nrofvalues;i++)
3185 if (lpkey->values[i].name==NULL)
3186 break;
3189 if (i == lpkey->nrofvalues)
3190 return ERROR_FILE_NOT_FOUND;
3192 val = lpkey->values+i;
3193 if (val->name) free(val->name);
3194 if (val->data) free(val->data);
3195 memcpy(
3196 lpkey->values+i,
3197 lpkey->values+i+1,
3198 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3200 lpkey->values = (LPKEYVALUE)xrealloc(
3201 lpkey->values,
3202 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3204 lpkey->nrofvalues--;
3205 return ERROR_SUCCESS;
3209 /******************************************************************************
3210 * RegDeleteValue32A [ADVAPI32.135]
3212 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPSTR lpszValue )
3214 LPWSTR lpszValueW;
3215 DWORD ret;
3217 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3218 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3219 ret = RegDeleteValueW( hkey, lpszValueW );
3220 if(lpszValueW) free(lpszValueW);
3221 return ret;
3225 /******************************************************************************
3226 * RegDeleteValue16 [KERNEL.222]
3228 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3230 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3231 return RegDeleteValueA( hkey, lpszValue );
3235 /******************************************************************************
3236 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3237 * Writes key to registry
3239 * PARAMS
3240 * hkey [I] Handle of key to write
3242 * RETURNS
3243 * Success: ERROR_SUCCESS
3244 * Failure: Error code
3246 DWORD WINAPI RegFlushKey( HKEY hkey )
3248 LPKEYSTRUCT lpkey;
3249 BOOL ret;
3251 TRACE(reg, "(%x)\n", hkey);
3253 lpkey = lookup_hkey( hkey );
3254 if (!lpkey)
3255 return ERROR_BADKEY;
3257 ERR(reg, "What is the correct filename?\n");
3259 ret = _savereg( lpkey, "foo.bar", TRUE);
3261 if( ret ) {
3262 return ERROR_SUCCESS;
3263 } else
3264 return ERROR_UNKNOWN; /* FIXME */
3268 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3271 /******************************************************************************
3272 * RegQueryInfoKey32W [ADVAPI32.153]
3274 * PARAMS
3275 * hkey [I] Handle to key to query
3276 * lpszClass [O] Buffer for class string
3277 * lpcchClass [O] Size of class string buffer
3278 * lpdwReserved [I] Reserved
3279 * lpcSubKeys [I] Buffer for number of subkeys
3280 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3281 * lpcchMaxClass [O] Buffer for longest class string length
3282 * lpcValues [O] Buffer for number of value entries
3283 * lpcchMaxValueName [O] Buffer for longest value name length
3284 * lpccbMaxValueData [O] Buffer for longest value data length
3285 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3286 * ft
3287 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3288 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3289 * lpcchClass is NULL
3290 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3291 * (it's hard to test validity, so test !NULL instead)
3293 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3294 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3295 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3296 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3297 LPDWORD lpcchMaxValueName,
3298 LPDWORD lpccbMaxValueData,
3299 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3301 LPKEYSTRUCT lpkey,lpxkey;
3302 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3303 int i;
3305 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3306 lpkey = lookup_hkey(hkey);
3307 if (!lpkey)
3308 return ERROR_INVALID_HANDLE;
3309 if (lpszClass) {
3310 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3311 return ERROR_INVALID_PARAMETER;
3313 /* either lpcchClass is valid or this is win95 and lpcchClass
3314 could be invalid */
3315 if (lpkey->class) {
3316 DWORD classLen = lstrlenW(lpkey->class);
3318 if (lpcchClass && classLen+1>*lpcchClass) {
3319 *lpcchClass=classLen+1;
3320 return ERROR_MORE_DATA;
3322 if (lpcchClass)
3323 *lpcchClass=classLen;
3324 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3325 } else {
3326 *lpszClass = 0;
3327 if (lpcchClass)
3328 *lpcchClass = 0;
3330 } else {
3331 if (lpcchClass)
3332 *lpcchClass = lstrlenW(lpkey->class);
3334 lpxkey=lpkey->nextsub;
3335 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3336 while (lpxkey) {
3337 nrofkeys++;
3338 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3339 maxsubkey=lstrlenW(lpxkey->keyname);
3340 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3341 maxclass=lstrlenW(lpxkey->class);
3342 lpxkey=lpxkey->next;
3344 for (i=0;i<lpkey->nrofvalues;i++) {
3345 LPKEYVALUE val=lpkey->values+i;
3347 if (val->name && lstrlenW(val->name)>maxvname)
3348 maxvname=lstrlenW(val->name);
3349 if (val->len>maxvdata)
3350 maxvdata=val->len;
3352 if (!maxclass) maxclass = 1;
3353 if (!maxvname) maxvname = 1;
3354 if (lpcValues)
3355 *lpcValues = lpkey->nrofvalues;
3356 if (lpcSubKeys)
3357 *lpcSubKeys = nrofkeys;
3358 if (lpcchMaxSubkey)
3359 *lpcchMaxSubkey = maxsubkey;
3360 if (lpcchMaxClass)
3361 *lpcchMaxClass = maxclass;
3362 if (lpcchMaxValueName)
3363 *lpcchMaxValueName= maxvname;
3364 if (lpccbMaxValueData)
3365 *lpccbMaxValueData= maxvdata;
3366 return ERROR_SUCCESS;
3370 /******************************************************************************
3371 * RegQueryInfoKey32A [ADVAPI32.152]
3373 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3374 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3375 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3376 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3377 LPDWORD lpccbMaxValueData,
3378 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3380 LPWSTR lpszClassW = NULL;
3381 DWORD ret;
3383 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3384 if (lpszClass) {
3385 if (lpcchClass) {
3386 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3387 } else if (VERSION_GetVersion() == WIN95) {
3388 /* win95 allows lpcchClass to be null */
3389 /* we don't know how big lpszClass is, would
3390 MAX_PATHNAME_LEN be the correct default? */
3391 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3394 } else
3395 lpszClassW = NULL;
3396 ret=RegQueryInfoKeyW(
3397 hkey,
3398 lpszClassW,
3399 lpcchClass,
3400 lpdwReserved,
3401 lpcSubKeys,
3402 lpcchMaxSubkey,
3403 lpcchMaxClass,
3404 lpcValues,
3405 lpcchMaxValueName,
3406 lpccbMaxValueData,
3407 lpcbSecurityDescriptor,
3410 if (ret==ERROR_SUCCESS && lpszClass)
3411 lstrcpyWtoA(lpszClass,lpszClassW);
3412 if (lpszClassW)
3413 free(lpszClassW);
3414 return ret;
3418 /******************************************************************************
3419 * RegConnectRegistry32W [ADVAPI32.128]
3421 * PARAMS
3422 * lpMachineName [I] Address of name of remote computer
3423 * hHey [I] Predefined registry handle
3424 * phkResult [I] Address of buffer for remote registry handle
3426 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3427 LPHKEY phkResult )
3429 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3431 if (!lpMachineName || !*lpMachineName) {
3432 /* Use the local machine name */
3433 return RegOpenKey16( hKey, "", phkResult );
3436 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3437 return ERROR_BAD_NETPATH;
3441 /******************************************************************************
3442 * RegConnectRegistry32A [ADVAPI32.127]
3444 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3446 DWORD ret;
3447 LPWSTR machineW = strdupA2W(machine);
3448 ret = RegConnectRegistryW( machineW, hkey, reskey );
3449 free(machineW);
3450 return ret;
3454 /******************************************************************************
3455 * RegGetKeySecurity [ADVAPI32.144]
3456 * Retrieves a copy of security descriptor protecting the registry key
3458 * PARAMS
3459 * hkey [I] Open handle of key to set
3460 * SecurityInformation [I] Descriptor contents
3461 * pSecurityDescriptor [O] Address of descriptor for key
3462 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3464 * RETURNS
3465 * Success: ERROR_SUCCESS
3466 * Failure: Error code
3468 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3469 SECURITY_INFORMATION SecurityInformation,
3470 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3471 LPDWORD lpcbSecurityDescriptor )
3473 LPKEYSTRUCT lpkey;
3475 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3476 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3478 lpkey = lookup_hkey( hkey );
3479 if (!lpkey)
3480 return ERROR_INVALID_HANDLE;
3482 /* FIXME: Check for valid SecurityInformation values */
3484 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3485 return ERROR_INSUFFICIENT_BUFFER;
3487 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3488 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3490 return ERROR_SUCCESS;
3494 /******************************************************************************
3495 * RegLoadKey32W [ADVAPI32.???]
3497 * PARAMS
3498 * hkey [I] Handle of open key
3499 * lpszSubKey [I] Address of name of subkey
3500 * lpszFile [I] Address of filename for registry information
3502 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3504 LPKEYSTRUCT lpkey;
3505 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3507 /* Do this check before the hkey check */
3508 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3509 return ERROR_INVALID_PARAMETER;
3511 lpkey = lookup_hkey( hkey );
3512 if (!lpkey)
3513 return ERROR_INVALID_HANDLE;
3515 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3516 debugstr_w(lpszFile));
3518 return ERROR_SUCCESS;
3522 /******************************************************************************
3523 * RegLoadKey32A [ADVAPI32.???]
3525 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3527 LONG ret;
3528 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3529 LPWSTR lpszFileW = strdupA2W(lpszFile);
3530 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3531 if(lpszFileW) free(lpszFileW);
3532 if(lpszSubKeyW) free(lpszSubKeyW);
3533 return ret;
3537 /******************************************************************************
3538 * RegNotifyChangeKeyValue [ADVAPI32.???]
3540 * PARAMS
3541 * hkey [I] Handle of key to watch
3542 * fWatchSubTree [I] Flag for subkey notification
3543 * fdwNotifyFilter [I] Changes to be reported
3544 * hEvent [I] Handle of signaled event
3545 * fAsync [I] Flag for asynchronous reporting
3547 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3548 DWORD fdwNotifyFilter, HANDLE hEvent,
3549 BOOL fAsync )
3551 LPKEYSTRUCT lpkey;
3552 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3553 hEvent,fAsync);
3555 lpkey = lookup_hkey( hkey );
3556 if (!lpkey)
3557 return ERROR_INVALID_HANDLE;
3559 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3560 hEvent,fAsync);
3562 return ERROR_SUCCESS;
3566 /******************************************************************************
3567 * RegUnLoadKey32W [ADVAPI32.173]
3569 * PARAMS
3570 * hkey [I] Handle of open key
3571 * lpSubKey [I] Address of name of subkey to unload
3573 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3575 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3576 return ERROR_SUCCESS;
3580 /******************************************************************************
3581 * RegUnLoadKey32A [ADVAPI32.172]
3583 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3585 LONG ret;
3586 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3587 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3588 if(lpSubKeyW) free(lpSubKeyW);
3589 return ret;
3593 /******************************************************************************
3594 * RegSetKeySecurity [ADVAPI32.167]
3596 * PARAMS
3597 * hkey [I] Open handle of key to set
3598 * SecurityInfo [I] Descriptor contents
3599 * pSecurityDesc [I] Address of descriptor for key
3601 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3602 PSECURITY_DESCRIPTOR pSecurityDesc )
3604 LPKEYSTRUCT lpkey;
3606 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3608 /* It seems to perform this check before the hkey check */
3609 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3610 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3611 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3612 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3613 /* Param OK */
3614 } else
3615 return ERROR_INVALID_PARAMETER;
3617 if (!pSecurityDesc)
3618 return ERROR_INVALID_PARAMETER;
3620 lpkey = lookup_hkey( hkey );
3621 if (!lpkey)
3622 return ERROR_INVALID_HANDLE;
3624 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3626 return ERROR_SUCCESS;
3630 /******************************************************************************
3631 * RegSaveKey32W [ADVAPI32.166]
3633 * PARAMS
3634 * hkey [I] Handle of key where save begins
3635 * lpFile [I] Address of filename to save to
3636 * sa [I] Address of security structure
3638 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3639 LPSECURITY_ATTRIBUTES sa )
3641 LPKEYSTRUCT lpkey;
3643 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3645 /* It appears to do this check before the hkey check */
3646 if (!lpFile || !*lpFile)
3647 return ERROR_INVALID_PARAMETER;
3649 lpkey = lookup_hkey( hkey );
3650 if (!lpkey)
3651 return ERROR_INVALID_HANDLE;
3653 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3655 return ERROR_SUCCESS;
3659 /******************************************************************************
3660 * RegSaveKey32A [ADVAPI32.165]
3662 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3663 LPSECURITY_ATTRIBUTES sa )
3665 LONG ret;
3666 LPWSTR lpFileW = strdupA2W(lpFile);
3667 ret = RegSaveKeyW( hkey, lpFileW, sa );
3668 free(lpFileW);
3669 return ret;
3673 /******************************************************************************
3674 * RegRestoreKey32W [ADVAPI32.164]
3676 * PARAMS
3677 * hkey [I] Handle of key where restore begins
3678 * lpFile [I] Address of filename containing saved tree
3679 * dwFlags [I] Optional flags
3681 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3683 LPKEYSTRUCT lpkey;
3685 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3687 /* It seems to do this check before the hkey check */
3688 if (!lpFile || !*lpFile)
3689 return ERROR_INVALID_PARAMETER;
3691 lpkey = lookup_hkey( hkey );
3692 if (!lpkey)
3693 return ERROR_INVALID_HANDLE;
3695 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3697 /* Check for file existence */
3699 return ERROR_SUCCESS;
3703 /******************************************************************************
3704 * RegRestoreKey32A [ADVAPI32.163]
3706 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3708 LONG ret;
3709 LPWSTR lpFileW = strdupA2W(lpFile);
3710 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3711 if(lpFileW) free(lpFileW);
3712 return ret;
3716 /******************************************************************************
3717 * RegReplaceKey32W [ADVAPI32.162]
3719 * PARAMS
3720 * hkey [I] Handle of open key
3721 * lpSubKey [I] Address of name of subkey
3722 * lpNewFile [I] Address of filename for file with new data
3723 * lpOldFile [I] Address of filename for backup file
3725 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3726 LPCWSTR lpOldFile )
3728 LPKEYSTRUCT lpkey;
3730 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3731 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3733 lpkey = lookup_hkey( hkey );
3734 if (!lpkey)
3735 return ERROR_INVALID_HANDLE;
3737 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3738 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3740 return ERROR_SUCCESS;
3744 /******************************************************************************
3745 * RegReplaceKey32A [ADVAPI32.161]
3747 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3748 LPCSTR lpOldFile )
3750 LONG ret;
3751 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3752 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3753 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3754 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3755 free(lpOldFileW);
3756 free(lpNewFileW);
3757 free(lpSubKeyW);
3758 return ret;