Fix redraw problems for ChooseColor dialog.
[wine.git] / misc / registry.c
blob47336cea9c23faf47be8dd49439bcba2a58d1188
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)*(lstrlen32W(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, INT32 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, INT32 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 += lstrlen32W(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 BOOL32 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 RegSetValueEx32A(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 BOOL32 _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;
683 TRACE(reg,"(void)\n");
685 all=0;
686 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
687 strcpy(buf,"yes");
688 } else {
689 DWORD len,junk,type;
691 len=4;
692 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
693 hkey,
694 VAL_SAVEUPDATED,
695 &junk,
696 &type,
697 buf,
698 &len
699 ))|| (type!=REG_SZ)
701 strcpy(buf,"yes");
702 RegCloseKey(hkey);
704 if (lstrcmpi32A(buf,"yes"))
705 all=1;
706 pwd=getpwuid(getuid());
707 if (pwd!=NULL && pwd->pw_dir!=NULL)
709 char *tmp;
711 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
712 strlen(SAVE_CURRENT_USER) + 2 );
713 strcpy(fn,pwd->pw_dir);
714 strcat(fn,WINE_PREFIX);
715 /* create the directory. don't care about errorcodes. */
716 mkdir(fn,0755); /* drwxr-xr-x */
717 strcat(fn,"/"SAVE_CURRENT_USER);
718 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
719 strcpy(tmp,fn);strcat(tmp,".tmp");
720 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
721 if (-1==rename(tmp,fn)) {
722 perror("rename tmp registry");
723 unlink(tmp);
726 free(tmp);
727 free(fn);
728 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
729 strcpy(fn,pwd->pw_dir);
730 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
731 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
732 strcpy(tmp,fn);strcat(tmp,".tmp");
733 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
734 if (-1==rename(tmp,fn)) {
735 perror("rename tmp registry");
736 unlink(tmp);
739 free(tmp);
740 free(fn);
741 } else
742 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
746 /************************ LOAD Registry Function ****************************/
750 /******************************************************************************
751 * _find_or_add_key [Internal]
753 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
755 LPKEYSTRUCT lpxkey,*lplpkey;
757 if ((!keyname) || (keyname[0]==0)) {
758 free(keyname);
759 return lpkey;
761 lplpkey= &(lpkey->nextsub);
762 lpxkey = *lplpkey;
763 while (lpxkey) {
764 if ( (lpxkey->keyname[0]==keyname[0]) &&
765 !lstrcmpi32W(lpxkey->keyname,keyname)
767 break;
768 lplpkey = &(lpxkey->next);
769 lpxkey = *lplpkey;
771 if (lpxkey==NULL) {
772 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
773 lpxkey = *lplpkey;
774 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
775 lpxkey->keyname = keyname;
776 } else
777 free(keyname);
778 return lpxkey;
781 /******************************************************************************
782 * _find_or_add_value [Internal]
784 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
785 LPBYTE data, DWORD len, DWORD lastmodified )
787 LPKEYVALUE val=NULL;
788 int i;
790 if (name && !*name) {/* empty string equals default (NULL) value */
791 free(name);
792 name = NULL;
795 for (i=0;i<lpkey->nrofvalues;i++) {
796 val=lpkey->values+i;
797 if (name==NULL) {
798 if (val->name==NULL)
799 break;
800 } else {
801 if ( val->name!=NULL &&
802 val->name[0]==name[0] &&
803 !lstrcmpi32W(val->name,name)
805 break;
808 if (i==lpkey->nrofvalues) {
809 lpkey->values = xrealloc(
810 lpkey->values,
811 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
813 val=lpkey->values+i;
814 memset(val,'\0',sizeof(KEYVALUE));
815 val->name = name;
816 } else {
817 if (name)
818 free(name);
820 if (val->lastmodified<lastmodified) {
821 val->lastmodified=lastmodified;
822 val->type = type;
823 val->len = len;
824 if (val->data)
825 free(val->data);
826 val->data = data;
827 } else
828 free(data);
832 /******************************************************************************
833 * _wine_read_line [Internal]
835 * reads a line including dynamically enlarging the readbuffer and throwing
836 * away comments
838 static int _wine_read_line( FILE *F, char **buf, int *len )
840 char *s,*curread;
841 int mylen,curoff;
843 curread = *buf;
844 mylen = *len;
845 **buf = '\0';
846 while (1) {
847 while (1) {
848 s=fgets(curread,mylen,F);
849 if (s==NULL)
850 return 0; /* EOF */
851 if (NULL==(s=strchr(curread,'\n'))) {
852 /* buffer wasn't large enough */
853 curoff = strlen(*buf);
854 *buf = xrealloc(*buf,*len*2);
855 curread = *buf + curoff;
856 mylen = *len; /* we filled up the buffer and
857 * got new '*len' bytes to fill
859 *len = *len * 2;
860 } else {
861 *s='\0';
862 break;
865 /* throw away comments */
866 if (**buf=='#' || **buf==';') {
867 curread = *buf;
868 mylen = *len;
869 continue;
871 if (s) /* got end of line */
872 break;
874 return 1;
878 /******************************************************************************
879 * _wine_read_USTRING [Internal]
881 * converts a char* into a UNICODE string (up to a special char)
882 * and returns the position exactly after that string
884 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
886 char *s;
887 LPWSTR ws;
889 /* read up to "=" or "\0" or "\n" */
890 s = buf;
891 if (*s == '=') {
892 /* empty string is the win3.1 default value(NULL)*/
893 *str = NULL;
894 return s;
896 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
897 ws = *str;
898 while (*s && (*s!='\n') && (*s!='=')) {
899 if (*s!='\\')
900 *ws++=*((unsigned char*)s++);
901 else {
902 s++;
903 if (!*s) {
904 /* Dangling \ ... may only happen if a registry
905 * write was short. FIXME: What do to?
907 break;
909 if (*s=='\\') {
910 *ws++='\\';
911 s++;
912 continue;
914 if (*s!='u') {
915 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
916 *ws++='\\';
917 *ws++=*s++;
918 } else {
919 char xbuf[5];
920 int wc;
922 s++;
923 memcpy(xbuf,s,4);xbuf[4]='\0';
924 if (!sscanf(xbuf,"%x",&wc))
925 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
926 s+=4;
927 *ws++ =(unsigned short)wc;
931 *ws = 0;
932 ws = *str;
933 if (*ws)
934 *str = strdupW(*str);
935 else
936 *str = NULL;
937 free(ws);
938 return s;
942 /******************************************************************************
943 * _wine_loadsubkey [Internal]
945 * NOTES
946 * It seems like this is returning a boolean. Should it?
948 * RETURNS
949 * Success: 1
950 * Failure: 0
952 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
953 int *buflen, DWORD optflag )
955 LPKEYSTRUCT lpxkey;
956 int i;
957 char *s;
958 LPWSTR name;
960 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
961 *buflen, optflag);
963 lpkey->flags |= optflag;
965 /* Good. We already got a line here ... so parse it */
966 lpxkey = NULL;
967 while (1) {
968 i=0;s=*buf;
969 while (*s=='\t') {
970 s++;
971 i++;
973 if (i>level) {
974 if (lpxkey==NULL) {
975 WARN(reg,"Got a subhierarchy without resp. key?\n");
976 return 0;
978 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
979 continue;
982 /* let the caller handle this line */
983 if (i<level || **buf=='\0')
984 return 1;
986 /* it can be: a value or a keyname. Parse the name first */
987 s=_wine_read_USTRING(s,&name);
989 /* switch() default: hack to avoid gotos */
990 switch (0) {
991 default:
992 if (*s=='\0') {
993 lpxkey=_find_or_add_key(lpkey,name);
994 } else {
995 LPBYTE data;
996 int len,lastmodified,type;
998 if (*s!='=') {
999 WARN(reg,"Unexpected character: %c\n",*s);
1000 break;
1002 s++;
1003 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1004 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1005 break;
1007 /* skip the 2 , */
1008 s=strchr(s,',');s++;
1009 s=strchr(s,',');s++;
1010 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1011 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1012 if (data)
1013 len = lstrlen32W((LPWSTR)data)*2+2;
1014 else
1015 len = 0;
1016 } else {
1017 len=strlen(s)/2;
1018 data = (LPBYTE)xmalloc(len+1);
1019 for (i=0;i<len;i++) {
1020 data[i]=0;
1021 if (*s>='0' && *s<='9')
1022 data[i]=(*s-'0')<<4;
1023 if (*s>='a' && *s<='f')
1024 data[i]=(*s-'a'+'\xa')<<4;
1025 if (*s>='A' && *s<='F')
1026 data[i]=(*s-'A'+'\xa')<<4;
1027 s++;
1028 if (*s>='0' && *s<='9')
1029 data[i]|=*s-'0';
1030 if (*s>='a' && *s<='f')
1031 data[i]|=*s-'a'+'\xa';
1032 if (*s>='A' && *s<='F')
1033 data[i]|=*s-'A'+'\xa';
1034 s++;
1037 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1040 /* read the next line */
1041 if (!_wine_read_line(F,buf,buflen))
1042 return 1;
1044 return 1;
1048 /******************************************************************************
1049 * _wine_loadsubreg [Internal]
1051 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1053 int ver;
1054 char *buf;
1055 int buflen;
1057 buf=xmalloc(10);buflen=10;
1058 if (!_wine_read_line(F,&buf,&buflen)) {
1059 free(buf);
1060 return 0;
1062 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1063 free(buf);
1064 return 0;
1066 if (ver!=REGISTRY_SAVE_VERSION) {
1067 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1068 free(buf);
1069 return 0;
1071 if (!_wine_read_line(F,&buf,&buflen)) {
1072 free(buf);
1073 return 0;
1075 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1076 free(buf);
1077 return 0;
1079 free(buf);
1080 return 1;
1084 /******************************************************************************
1085 * _wine_loadreg [Internal]
1087 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1089 FILE *F;
1091 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1093 F = fopen(fn,"rb");
1094 if (F==NULL) {
1095 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1096 return;
1098 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1099 fclose(F);
1100 unlink(fn);
1101 return;
1103 fclose(F);
1107 /******************************************************************************
1108 * _copy_registry [Internal]
1110 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1112 LPKEYSTRUCT lpxkey;
1113 int j;
1114 LPKEYVALUE valfrom;
1116 from=from->nextsub;
1117 while (from) {
1118 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1120 for (j=0;j<from->nrofvalues;j++) {
1121 LPWSTR name;
1122 LPBYTE data;
1124 valfrom = from->values+j;
1125 name=valfrom->name;
1126 if (name) name=strdupW(name);
1127 data=(LPBYTE)xmalloc(valfrom->len);
1128 memcpy(data,valfrom->data,valfrom->len);
1130 _find_or_add_value(
1131 lpxkey,
1132 name,
1133 valfrom->type,
1134 data,
1135 valfrom->len,
1136 valfrom->lastmodified
1139 _copy_registry(from,lpxkey);
1140 from = from->next;
1145 /* WINDOWS 95 REGISTRY LOADER */
1147 * Structure of a win95 registry database.
1148 * main header:
1149 * 0 : "CREG" - magic
1150 * 4 : DWORD version
1151 * 8 : DWORD offset_of_RGDB_part
1152 * 0C..0F: ? (someone fill in please)
1153 * 10: WORD number of RGDB blocks
1154 * 12: WORD ?
1155 * 14: WORD always 0000?
1156 * 16: WORD always 0001?
1157 * 18..1F: ? (someone fill in please)
1159 * 20: RGKN_section:
1160 * header:
1161 * 0 : "RGKN" - magic
1162 * 4 : DWORD offset to first RGDB section
1163 * 8 : DWORD offset to the root record
1164 * C..0x1B: ? (fill in)
1165 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1167 * Disk Key Entry Structure:
1168 * 00: DWORD - Free entry indicator(?)
1169 * 04: DWORD - Hash = sum of bytes of keyname
1170 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1171 * 0C: DWORD - disk address of PreviousLevel Key.
1172 * 10: DWORD - disk address of Next Sublevel Key.
1173 * 14: DWORD - disk address of Next Key (on same level).
1174 * DKEP>18: WORD - Nr, Low Significant part.
1175 * 1A: WORD - Nr, High Significant part.
1177 * The disk address always points to the nr part of the previous key entry
1178 * of the referenced key. Don't ask me why, or even if I got this correct
1179 * from staring at 1kg of hexdumps. (DKEP)
1181 * The High significant part of the structure seems to equal the number
1182 * of the RGDB section. The low significant part is a unique ID within
1183 * that RGDB section
1185 * There are two minor corrections to the position of that structure.
1186 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1187 * the DKE reread from there.
1188 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1189 * CPS - I have not experienced the above phenomenon in my registry files
1191 * RGDB_section:
1192 * 00: "RGDB" - magic
1193 * 04: DWORD offset to next RGDB section
1194 * 08: DWORD ?
1195 * 0C: WORD always 000d?
1196 * 0E: WORD RGDB block number
1197 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1198 * 14..1F: ?
1199 * 20.....: disk keys
1201 * disk key:
1202 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1203 * 08: WORD nrLS - low significant part of NR
1204 * 0A: WORD nrHS - high significant part of NR
1205 * 0C: DWORD bytesused - bytes used in this structure.
1206 * 10: WORD name_len - length of name in bytes. without \0
1207 * 12: WORD nr_of_values - number of values.
1208 * 14: char name[name_len] - name string. No \0.
1209 * 14+name_len: disk values
1210 * nextkeyoffset: ... next disk key
1212 * disk value:
1213 * 00: DWORD type - value type (hmm, could be WORD too)
1214 * 04: DWORD - unknown, usually 0
1215 * 08: WORD namelen - length of Name. 0 means name=NULL
1216 * 0C: WORD datalen - length of Data.
1217 * 10: char name[namelen] - name, no \0
1218 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1219 * 10+namelen+datalen: next values or disk key
1221 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1222 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1223 * structure) and reading another RGDB_section.
1224 * repeat until end of file.
1226 * An interesting relationship exists in RGDB_section. The value at offset
1227 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1228 * idea at the moment what this means. (Kevin Cozens)
1230 * FIXME: this description needs some serious help, yes.
1233 struct _w95keyvalue {
1234 unsigned long type;
1235 unsigned short datalen;
1236 char *name;
1237 unsigned char *data;
1238 unsigned long x1;
1239 int lastmodified;
1242 struct _w95key {
1243 char *name;
1244 int nrofvals;
1245 struct _w95keyvalue *values;
1246 struct _w95key *prevlvl;
1247 struct _w95key *nextsub;
1248 struct _w95key *next;
1252 struct _w95_info {
1253 char *rgknbuffer;
1254 int rgknsize;
1255 char *rgdbbuffer;
1256 int rgdbsize;
1257 int depth;
1258 int lastmodified;
1262 /******************************************************************************
1263 * _w95_processKey [Internal]
1265 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1266 int nrLS, int nrMS, struct _w95_info *info )
1269 /* Disk Key Header structure (RGDB part) */
1270 struct dkh {
1271 unsigned long nextkeyoff;
1272 unsigned short nrLS;
1273 unsigned short nrMS;
1274 unsigned long bytesused;
1275 unsigned short keynamelen;
1276 unsigned short values;
1277 unsigned long xx1;
1278 /* keyname */
1279 /* disk key values or nothing */
1281 /* Disk Key Value structure */
1282 struct dkv {
1283 unsigned long type;
1284 unsigned long x1;
1285 unsigned short valnamelen;
1286 unsigned short valdatalen;
1287 /* valname, valdata */
1291 struct dkh dkh;
1292 int bytesread = 0;
1293 char *rgdbdata = info->rgdbbuffer;
1294 int nbytes = info->rgdbsize;
1295 char *curdata = rgdbdata;
1296 char *end = rgdbdata + nbytes;
1297 int off_next_rgdb;
1298 char *next = rgdbdata;
1299 int nrgdb, i;
1300 LPKEYSTRUCT lpxkey;
1302 do {
1303 curdata = next;
1304 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1306 memcpy(&off_next_rgdb,curdata+4,4);
1307 next = curdata + off_next_rgdb;
1308 nrgdb = (int) *((short *)curdata + 7);
1310 } while (nrgdb != nrMS && (next < end));
1312 /* curdata now points to the start of the right RGDB section */
1313 curdata += 0x20;
1315 #define XREAD(whereto,len) \
1316 if ((curdata + len) <end) {\
1317 memcpy(whereto,curdata,len);\
1318 curdata+=len;\
1319 bytesread+=len;\
1322 while (curdata < next) {
1323 struct dkh *xdkh = (struct dkh*)curdata;
1325 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1326 if (xdkh->nrLS == nrLS) {
1327 memcpy(&dkh,xdkh,sizeof(dkh));
1328 curdata += sizeof(dkh);
1329 break;
1331 curdata += xdkh->nextkeyoff;
1334 if (dkh.nrLS != nrLS) return (NULL);
1336 if (nrgdb != dkh.nrMS)
1337 return (NULL);
1339 assert((dkh.keynamelen<2) || curdata[0]);
1340 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1341 curdata += dkh.keynamelen;
1343 for (i=0;i< dkh.values; i++) {
1344 struct dkv dkv;
1345 LPBYTE data;
1346 int len;
1347 LPWSTR name;
1349 XREAD(&dkv,sizeof(dkv));
1351 name = strcvtA2W(curdata, dkv.valnamelen);
1352 curdata += dkv.valnamelen;
1354 if ((1 << dkv.type) & UNICONVMASK) {
1355 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1356 len = 2*(dkv.valdatalen + 1);
1357 } else {
1358 /* I don't think we want to NULL terminate all data */
1359 data = xmalloc(dkv.valdatalen);
1360 memcpy (data, curdata, dkv.valdatalen);
1361 len = dkv.valdatalen;
1364 curdata += dkv.valdatalen;
1366 _find_or_add_value(
1367 lpxkey,
1368 name,
1369 dkv.type,
1370 data,
1371 len,
1372 info->lastmodified
1375 return (lpxkey);
1378 /******************************************************************************
1379 * _w95_walkrgkn [Internal]
1381 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1382 struct _w95_info *info )
1385 /* Disk Key Entry structure (RGKN part) */
1386 struct dke {
1387 unsigned long x1;
1388 unsigned long x2;
1389 unsigned long x3;/*usually 0xFFFFFFFF */
1390 unsigned long prevlvl;
1391 unsigned long nextsub;
1392 unsigned long next;
1393 unsigned short nrLS;
1394 unsigned short nrMS;
1395 } *dke = (struct dke *)off;
1396 LPKEYSTRUCT lpxkey;
1398 if (dke == NULL) {
1399 dke = (struct dke *) ((char *)info->rgknbuffer);
1402 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1403 /* XXX <-- This is a hack*/
1404 if (!lpxkey) {
1405 lpxkey = prevkey;
1408 if (dke->nextsub != -1 &&
1409 ((dke->nextsub - 0x20) < info->rgknsize)
1410 && (dke->nextsub > 0x20)) {
1412 _w95_walkrgkn(lpxkey,
1413 info->rgknbuffer + dke->nextsub - 0x20,
1414 info);
1417 if (dke->next != -1 &&
1418 ((dke->next - 0x20) < info->rgknsize) &&
1419 (dke->next > 0x20)) {
1420 _w95_walkrgkn(prevkey,
1421 info->rgknbuffer + dke->next - 0x20,
1422 info);
1425 return;
1429 /******************************************************************************
1430 * _w95_loadreg [Internal]
1432 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1434 HFILE32 hfd;
1435 char magic[5];
1436 unsigned long where,version,rgdbsection,end;
1437 struct _w95_info info;
1438 OFSTRUCT ofs;
1439 BY_HANDLE_FILE_INFORMATION hfdinfo;
1441 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1442 hfd=OpenFile32(fn,&ofs,OF_READ);
1443 if (hfd==HFILE_ERROR32)
1444 return;
1445 magic[4]=0;
1446 if (4!=_lread32(hfd,magic,4))
1447 return;
1448 if (strcmp(magic,"CREG")) {
1449 WARN(reg,"%s is not a w95 registry.\n",fn);
1450 return;
1452 if (4!=_lread32(hfd,&version,4))
1453 return;
1454 if (4!=_lread32(hfd,&rgdbsection,4))
1455 return;
1456 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1457 return;
1458 if (4!=_lread32(hfd,magic,4))
1459 return;
1460 if (strcmp(magic,"RGKN")) {
1461 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1462 return;
1465 /* STEP 1: Keylink structures */
1466 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1467 return;
1468 where = 0x40;
1469 end = rgdbsection;
1471 info.rgknsize = end - where;
1472 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1473 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1474 return;
1476 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1477 return;
1479 end = hfdinfo.nFileSizeLow;
1480 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1482 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1483 return;
1485 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1486 info.rgdbsize = end - rgdbsection;
1488 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1489 return;
1490 _lclose32(hfd);
1492 _w95_walkrgkn(lpkey, NULL, &info);
1494 free (info.rgdbbuffer);
1495 free (info.rgknbuffer);
1499 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1502 reghack - windows 3.11 registry data format demo program.
1504 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1505 a combined hash table and tree description, and finally a text table.
1507 The header is obvious from the struct header. The taboff1 and taboff2
1508 fields are always 0x20, and their usage is unknown.
1510 The 8-byte entry table has various entry types.
1512 tabent[0] is a root index. The second word has the index of the root of
1513 the directory.
1514 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1515 the index of the key/value that has that hash. Data with the same
1516 hash value are on a circular list. The other three words in the
1517 hash entry are always zero.
1518 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1519 entry: dirent and keyent/valent. They are identified by context.
1520 tabent[freeidx] is the first free entry. The first word in a free entry
1521 is the index of the next free entry. The last has 0 as a link.
1522 The other three words in the free list are probably irrelevant.
1524 Entries in text table are preceeded by a word at offset-2. This word
1525 has the value (2*index)+1, where index is the referring keyent/valent
1526 entry in the table. I have no suggestion for the 2* and the +1.
1527 Following the word, there are N bytes of data, as per the keyent/valent
1528 entry length. The offset of the keyent/valent entry is from the start
1529 of the text table to the first data byte.
1531 This information is not available from Microsoft. The data format is
1532 deduced from the reg.dat file by me. Mistakes may
1533 have been made. I claim no rights and give no guarantees for this program.
1535 Tor Sjøwall, tor@sn.no
1538 /* reg.dat header format */
1539 struct _w31_header {
1540 char cookie[8]; /* 'SHCC3.10' */
1541 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1542 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1543 unsigned long tabcnt; /* number of entries in index table */
1544 unsigned long textoff; /* offset of text part */
1545 unsigned long textsize; /* byte size of text part */
1546 unsigned short hashsize; /* hash size */
1547 unsigned short freeidx; /* free index */
1550 /* generic format of table entries */
1551 struct _w31_tabent {
1552 unsigned short w0, w1, w2, w3;
1555 /* directory tabent: */
1556 struct _w31_dirent {
1557 unsigned short sibling_idx; /* table index of sibling dirent */
1558 unsigned short child_idx; /* table index of child dirent */
1559 unsigned short key_idx; /* table index of key keyent */
1560 unsigned short value_idx; /* table index of value valent */
1563 /* key tabent: */
1564 struct _w31_keyent {
1565 unsigned short hash_idx; /* hash chain index for string */
1566 unsigned short refcnt; /* reference count */
1567 unsigned short length; /* length of string */
1568 unsigned short string_off; /* offset of string in text table */
1571 /* value tabent: */
1572 struct _w31_valent {
1573 unsigned short hash_idx; /* hash chain index for string */
1574 unsigned short refcnt; /* reference count */
1575 unsigned short length; /* length of string */
1576 unsigned short string_off; /* offset of string in text table */
1579 /* recursive helper function to display a directory tree */
1580 void
1581 __w31_dumptree( unsigned short idx,
1582 unsigned char *txt,
1583 struct _w31_tabent *tab,
1584 struct _w31_header *head,
1585 LPKEYSTRUCT lpkey,
1586 time_t lastmodified,
1587 int level
1589 struct _w31_dirent *dir;
1590 struct _w31_keyent *key;
1591 struct _w31_valent *val;
1592 LPKEYSTRUCT xlpkey = NULL;
1593 LPWSTR name,value;
1594 static char tail[400];
1596 while (idx!=0) {
1597 dir=(struct _w31_dirent*)&tab[idx];
1599 if (dir->key_idx) {
1600 key = (struct _w31_keyent*)&tab[dir->key_idx];
1602 memcpy(tail,&txt[key->string_off],key->length);
1603 tail[key->length]='\0';
1604 /* all toplevel entries AND the entries in the
1605 * toplevel subdirectory belong to \SOFTWARE\Classes
1607 if (!level && !lstrcmp32A(tail,".classes")) {
1608 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1609 idx=dir->sibling_idx;
1610 continue;
1612 name=strdupA2W(tail);
1614 xlpkey=_find_or_add_key(lpkey,name);
1616 /* only add if leaf node or valued node */
1617 if (dir->value_idx!=0||dir->child_idx==0) {
1618 if (dir->value_idx) {
1619 val=(struct _w31_valent*)&tab[dir->value_idx];
1620 memcpy(tail,&txt[val->string_off],val->length);
1621 tail[val->length]='\0';
1622 value=strdupA2W(tail);
1623 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1626 } else {
1627 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1629 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1630 idx=dir->sibling_idx;
1635 /******************************************************************************
1636 * _w31_loadreg [Internal]
1638 void _w31_loadreg(void) {
1639 HFILE32 hf;
1640 struct _w31_header head;
1641 struct _w31_tabent *tab;
1642 unsigned char *txt;
1643 int len;
1644 OFSTRUCT ofs;
1645 BY_HANDLE_FILE_INFORMATION hfinfo;
1646 time_t lastmodified;
1647 LPKEYSTRUCT lpkey;
1649 TRACE(reg,"(void)\n");
1651 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1652 if (hf==HFILE_ERROR32)
1653 return;
1655 /* read & dump header */
1656 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1657 ERR(reg, "reg.dat is too short.\n");
1658 _lclose32(hf);
1659 return;
1661 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1662 ERR(reg, "reg.dat has bad signature.\n");
1663 _lclose32(hf);
1664 return;
1667 len = head.tabcnt * sizeof(struct _w31_tabent);
1668 /* read and dump index table */
1669 tab = xmalloc(len);
1670 if (len!=_lread32(hf,tab,len)) {
1671 ERR(reg,"couldn't read %d bytes.\n",len);
1672 free(tab);
1673 _lclose32(hf);
1674 return;
1677 /* read text */
1678 txt = xmalloc(head.textsize);
1679 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1680 ERR(reg,"couldn't seek to textblock.\n");
1681 free(tab);
1682 free(txt);
1683 _lclose32(hf);
1684 return;
1686 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1687 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1688 free(tab);
1689 free(txt);
1690 _lclose32(hf);
1691 return;
1694 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1695 ERR(reg,"GetFileInformationByHandle failed?.\n");
1696 free(tab);
1697 free(txt);
1698 _lclose32(hf);
1699 return;
1701 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1702 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1703 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1704 free(tab);
1705 free(txt);
1706 _lclose32(hf);
1707 return;
1711 /**********************************************************************************
1712 * SHELL_LoadRegistry [Internal]
1714 void SHELL_LoadRegistry( void )
1716 char *fn;
1717 struct passwd *pwd;
1718 LPKEYSTRUCT lpkey;
1719 HKEY hkey;
1721 TRACE(reg,"(void)\n");
1723 /* Load windows 3.1 entries */
1724 _w31_loadreg();
1725 /* Load windows 95 entries */
1726 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE));
1727 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE));
1728 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS));
1730 /* the global user default is loaded under HKEY_USERS\\.Default */
1731 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1732 lpkey = lookup_hkey(hkey);
1733 if(!lpkey)
1734 WARN(reg,"Could not create global user default key\n");
1735 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1737 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1738 _copy_registry(lpkey,lookup_hkey(HKEY_CURRENT_USER));
1739 RegCloseKey(hkey);
1741 /* the global machine defaults */
1742 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),SAVE_LOCAL_MACHINE_DEFAULT,0);
1744 /* load the user saved registries */
1746 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1748 pwd=getpwuid(getuid());
1749 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1750 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1751 strcpy(fn,pwd->pw_dir);
1752 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1753 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,REG_OPTION_TAINTED);
1754 free(fn);
1755 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1756 strcpy(fn,pwd->pw_dir);
1757 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1758 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),fn,REG_OPTION_TAINTED);
1759 free(fn);
1760 } else
1761 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1762 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1763 DWORD junk,type,len;
1764 char data[5];
1766 len=4;
1767 if (( RegQueryValueEx32A(
1768 hkey,
1769 VAL_SAVEUPDATED,
1770 &junk,
1771 &type,
1772 data,
1773 &len
1774 )!=ERROR_SUCCESS) ||
1775 type != REG_SZ
1777 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1778 RegCloseKey(hkey);
1783 /********************* API FUNCTIONS ***************************************/
1785 * Open Keys.
1787 * All functions are stubs to RegOpenKeyEx32W where all the
1788 * magic happens.
1790 * Callpath:
1791 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1792 * RegOpenKey32W -> RegOpenKeyEx32W
1796 /******************************************************************************
1797 * RegOpenKeyEx32W [ADVAPI32.150]
1798 * Opens the specified key
1800 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1802 * PARAMS
1803 * hkey [I] Handle of open key
1804 * lpszSubKey [I] Name of subkey to open
1805 * dwReserved [I] Reserved - must be zero
1806 * samDesired [I] Security access mask
1807 * retkey [O] Address of handle of open key
1809 * RETURNS
1810 * Success: ERROR_SUCCESS
1811 * Failure: Error code
1813 DWORD WINAPI RegOpenKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
1814 REGSAM samDesired, LPHKEY retkey )
1816 LPKEYSTRUCT lpNextKey,lpxkey;
1817 LPWSTR *wps;
1818 int wpc,i;
1820 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1821 samDesired,retkey);
1823 lpNextKey = lookup_hkey( hkey );
1824 if (!lpNextKey)
1825 return ERROR_INVALID_HANDLE;
1827 if (!lpszSubKey || !*lpszSubKey) {
1828 /* Either NULL or pointer to empty string, so return a new handle
1829 to the original hkey */
1830 currenthandle += 2;
1831 add_handle(currenthandle,lpNextKey,samDesired);
1832 *retkey=currenthandle;
1833 return ERROR_SUCCESS;
1836 if (lpszSubKey[0] == '\\') {
1837 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1838 return ERROR_BAD_PATHNAME;
1841 split_keypath(lpszSubKey,&wps,&wpc);
1842 i = 0;
1843 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1844 lpxkey = lpNextKey;
1846 while (wps[i]) {
1847 lpxkey=lpNextKey->nextsub;
1848 while (lpxkey) {
1849 if (!lstrcmpi32W(wps[i],lpxkey->keyname)) {
1850 break;
1852 lpxkey=lpxkey->next;
1855 if (!lpxkey) {
1856 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1857 FREE_KEY_PATH;
1858 return ERROR_FILE_NOT_FOUND;
1860 i++;
1861 lpNextKey = lpxkey;
1864 currenthandle += 2;
1865 add_handle(currenthandle,lpxkey,samDesired);
1866 *retkey = currenthandle;
1867 TRACE(reg," Returning %x\n", currenthandle);
1868 FREE_KEY_PATH;
1869 return ERROR_SUCCESS;
1873 /******************************************************************************
1874 * RegOpenKeyEx32A [ADVAPI32.149]
1876 DWORD WINAPI RegOpenKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1877 REGSAM samDesired, LPHKEY retkey )
1879 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1880 DWORD ret;
1882 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1883 samDesired,retkey);
1884 ret = RegOpenKeyEx32W( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
1885 free(lpszSubKeyW);
1886 return ret;
1890 /******************************************************************************
1891 * RegOpenKey32W [ADVAPI32.151]
1893 * PARAMS
1894 * hkey [I] Handle of open key
1895 * lpszSubKey [I] Address of name of subkey to open
1896 * retkey [O] Address of handle of open key
1898 * RETURNS
1899 * Success: ERROR_SUCCESS
1900 * Failure: Error code
1902 DWORD WINAPI RegOpenKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1904 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
1905 return RegOpenKeyEx32W( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1909 /******************************************************************************
1910 * RegOpenKey32A [ADVAPI32.148]
1912 DWORD WINAPI RegOpenKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1914 DWORD ret;
1915 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1916 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1917 ret = RegOpenKey32W( hkey, lpszSubKeyW, retkey );
1918 free(lpszSubKeyW);
1919 return ret;
1923 /******************************************************************************
1924 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1926 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1928 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1929 return RegOpenKey32A( hkey, lpszSubKey, retkey );
1934 * Create keys
1936 * All those functions convert their respective
1937 * arguments and call RegCreateKeyExW at the end.
1939 * We stay away from the Ex functions as long as possible because there are
1940 * differences in the return values
1942 * Callpath:
1943 * RegCreateKeyEx32A \
1944 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1948 /******************************************************************************
1949 * RegCreateKeyEx32W [ADVAPI32.131]
1951 * PARAMS
1952 * hkey [I] Handle of an open key
1953 * lpszSubKey [I] Address of subkey name
1954 * dwReserved [I] Reserved - must be 0
1955 * lpszClass [I] Address of class string
1956 * fdwOptions [I] Special options flag
1957 * samDesired [I] Desired security access
1958 * lpSecAttribs [I] Address of key security structure
1959 * retkey [O] Address of buffer for opened handle
1960 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1962 DWORD WINAPI RegCreateKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey,
1963 DWORD dwReserved, LPWSTR lpszClass,
1964 DWORD fdwOptions, REGSAM samDesired,
1965 LPSECURITY_ATTRIBUTES lpSecAttribs,
1966 LPHKEY retkey, LPDWORD lpDispos )
1968 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1969 LPWSTR *wps;
1970 int wpc,i;
1972 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
1973 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
1974 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
1976 lpNextKey = lookup_hkey(hkey);
1977 if (!lpNextKey)
1978 return ERROR_INVALID_HANDLE;
1980 /* Check for valid options */
1981 switch(fdwOptions) {
1982 case REG_OPTION_NON_VOLATILE:
1983 case REG_OPTION_VOLATILE:
1984 case REG_OPTION_BACKUP_RESTORE:
1985 break;
1986 default:
1987 return ERROR_INVALID_PARAMETER;
1990 /* Sam has to be a combination of the following */
1991 if (!(samDesired &
1992 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
1993 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
1994 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
1995 return ERROR_INVALID_PARAMETER;
1997 if (!lpszSubKey || !*lpszSubKey) {
1998 currenthandle += 2;
1999 add_handle(currenthandle,lpNextKey,samDesired);
2000 *retkey=currenthandle;
2001 TRACE(reg, "Returning %x\n", currenthandle);
2002 lpNextKey->flags|=REG_OPTION_TAINTED;
2003 return ERROR_SUCCESS;
2006 if (lpszSubKey[0] == '\\') {
2007 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2008 return ERROR_BAD_PATHNAME;
2011 split_keypath(lpszSubKey,&wps,&wpc);
2012 i = 0;
2013 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2014 lpxkey = lpNextKey;
2015 while (wps[i]) {
2016 lpxkey=lpNextKey->nextsub;
2017 while (lpxkey) {
2018 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2019 break;
2020 lpxkey=lpxkey->next;
2022 if (!lpxkey)
2023 break;
2024 i++;
2025 lpNextKey = lpxkey;
2027 if (lpxkey) {
2028 currenthandle += 2;
2029 add_handle(currenthandle,lpxkey,samDesired);
2030 lpxkey->flags |= REG_OPTION_TAINTED;
2031 *retkey = currenthandle;
2032 TRACE(reg, "Returning %x\n", currenthandle);
2033 if (lpDispos)
2034 *lpDispos = REG_OPENED_EXISTING_KEY;
2035 FREE_KEY_PATH;
2036 return ERROR_SUCCESS;
2039 /* Good. Now the hard part */
2040 while (wps[i]) {
2041 lplpPrevKey = &(lpNextKey->nextsub);
2042 lpxkey = *lplpPrevKey;
2043 while (lpxkey) {
2044 lplpPrevKey = &(lpxkey->next);
2045 lpxkey = *lplpPrevKey;
2047 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2048 if (!*lplpPrevKey) {
2049 FREE_KEY_PATH;
2050 TRACE(reg, "Returning OUTOFMEMORY\n");
2051 return ERROR_OUTOFMEMORY;
2053 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2054 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2055 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2056 (*lplpPrevKey)->next = NULL;
2057 (*lplpPrevKey)->nextsub = NULL;
2058 (*lplpPrevKey)->values = NULL;
2059 (*lplpPrevKey)->nrofvalues = 0;
2060 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2061 if (lpszClass)
2062 (*lplpPrevKey)->class = strdupW(lpszClass);
2063 else
2064 (*lplpPrevKey)->class = NULL;
2065 lpNextKey = *lplpPrevKey;
2066 i++;
2068 currenthandle += 2;
2069 add_handle(currenthandle,lpNextKey,samDesired);
2071 /*FIXME: flag handling correct? */
2072 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2073 if (lpszClass)
2074 lpNextKey->class = strdupW(lpszClass);
2075 else
2076 lpNextKey->class = NULL;
2077 *retkey = currenthandle;
2078 TRACE(reg, "Returning %x\n", currenthandle);
2079 if (lpDispos)
2080 *lpDispos = REG_CREATED_NEW_KEY;
2081 FREE_KEY_PATH;
2082 return ERROR_SUCCESS;
2086 /******************************************************************************
2087 * RegCreateKeyEx32A [ADVAPI32.130]
2089 DWORD WINAPI RegCreateKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2090 LPSTR lpszClass, DWORD fdwOptions,
2091 REGSAM samDesired,
2092 LPSECURITY_ATTRIBUTES lpSecAttribs,
2093 LPHKEY retkey, LPDWORD lpDispos )
2095 LPWSTR lpszSubKeyW, lpszClassW;
2096 DWORD ret;
2098 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2099 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2100 retkey,lpDispos);
2102 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2103 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2105 ret = RegCreateKeyEx32W( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2106 fdwOptions, samDesired, lpSecAttribs, retkey,
2107 lpDispos );
2109 if(lpszSubKeyW) free(lpszSubKeyW);
2110 if(lpszClassW) free(lpszClassW);
2112 return ret;
2116 /******************************************************************************
2117 * RegCreateKey32W [ADVAPI32.132]
2119 DWORD WINAPI RegCreateKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2121 DWORD junk;
2122 LPKEYSTRUCT lpNextKey;
2124 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2126 /* This check is here because the return value is different than the
2127 one from the Ex functions */
2128 lpNextKey = lookup_hkey(hkey);
2129 if (!lpNextKey)
2130 return ERROR_BADKEY;
2132 return RegCreateKeyEx32W( hkey, lpszSubKey, 0, NULL,
2133 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2134 retkey, &junk);
2138 /******************************************************************************
2139 * RegCreateKey32A [ADVAPI32.129]
2141 DWORD WINAPI RegCreateKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2143 DWORD ret;
2144 LPWSTR lpszSubKeyW;
2146 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2147 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2148 ret = RegCreateKey32W( hkey, lpszSubKeyW, retkey );
2149 if(lpszSubKeyW) free(lpszSubKeyW);
2150 return ret;
2154 /******************************************************************************
2155 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2157 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2159 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2160 return RegCreateKey32A( hkey, lpszSubKey, retkey );
2165 * Query Value Functions
2166 * Win32 differs between keynames and valuenames.
2167 * multiple values may belong to one key, the special value
2168 * with name NULL is the default value used by the win31
2169 * compat functions.
2171 * Callpath:
2172 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2173 * RegQueryValue32W -> RegQueryValueEx32W
2177 /******************************************************************************
2178 * RegQueryValueEx32W [ADVAPI32.158]
2179 * Retrieves type and data for a specified name associated with an open key
2181 * PARAMS
2182 * hkey [I] Handle of key to query
2183 * lpValueName [I] Name of value to query
2184 * lpdwReserved [I] Reserved - must be NULL
2185 * lpdwType [O] Address of buffer for value type. If NULL, the type
2186 * is not required.
2187 * lpbData [O] Address of data buffer. If NULL, the actual data is
2188 * not required.
2189 * lpcbData [I/O] Address of data buffer size
2191 * RETURNS
2192 * ERROR_SUCCESS: Success
2193 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2194 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2196 DWORD WINAPI RegQueryValueEx32W( HKEY hkey, LPWSTR lpValueName,
2197 LPDWORD lpdwReserved, LPDWORD lpdwType,
2198 LPBYTE lpbData, LPDWORD lpcbData )
2200 LPKEYSTRUCT lpkey;
2201 int i;
2202 DWORD ret;
2204 TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2205 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2207 lpkey = lookup_hkey(hkey);
2209 if (!lpkey)
2210 return ERROR_INVALID_HANDLE;
2212 if ((lpbData && ! lpcbData) || lpdwReserved)
2213 return ERROR_INVALID_PARAMETER;
2215 /* An empty name string is equivalent to NULL */
2216 if (lpValueName && !*lpValueName)
2217 lpValueName = NULL;
2219 if (lpValueName==NULL)
2220 { /* Use key's unnamed or default value, if any */
2221 for (i=0;i<lpkey->nrofvalues;i++)
2222 if (lpkey->values[i].name==NULL)
2223 break;
2225 else
2226 { /* Search for the key name */
2227 for (i=0;i<lpkey->nrofvalues;i++)
2228 if ( lpkey->values[i].name && !lstrcmpi32W(lpValueName,lpkey->values[i].name))
2229 break;
2232 if (i==lpkey->nrofvalues)
2233 { TRACE(reg," Key not found\n");
2234 if (lpValueName==NULL)
2235 { /* Empty keyname not found */
2236 if (lpbData)
2237 { *(WCHAR*)lpbData = 0;
2238 *lpcbData = 2;
2240 if (lpdwType)
2241 *lpdwType = REG_SZ;
2242 TRACE(reg, " Returning an empty string\n");
2243 return ERROR_SUCCESS;
2245 return ERROR_FILE_NOT_FOUND;
2248 ret = ERROR_SUCCESS;
2250 if (lpdwType) /* type required ?*/
2251 *lpdwType = lpkey->values[i].type;
2253 if (lpbData) /* data required ?*/
2254 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2255 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2256 else
2257 ret = ERROR_MORE_DATA;
2260 if (lpcbData) /* size required ?*/
2261 { *lpcbData = lpkey->values[i].len;
2264 debug_print_value ( lpbData, lpkey->values[i].type, lpkey->values[i].len);
2266 TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2268 return ret;
2272 /******************************************************************************
2273 * RegQueryValue32W [ADVAPI32.159]
2275 DWORD WINAPI RegQueryValue32W( HKEY hkey, LPWSTR lpszSubKey, LPWSTR lpszData,
2276 LPDWORD lpcbData )
2278 HKEY xhkey;
2279 DWORD ret,lpdwType;
2281 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2282 lpcbData?*lpcbData:0);
2284 /* Only open subkey, if we really do descend */
2285 if (lpszSubKey && *lpszSubKey) {
2286 ret = RegOpenKey32W( hkey, lpszSubKey, &xhkey );
2287 if (ret != ERROR_SUCCESS) {
2288 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2289 return ret;
2291 } else
2292 xhkey = hkey;
2294 lpdwType = REG_SZ;
2295 ret = RegQueryValueEx32W( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2296 lpcbData );
2297 if (xhkey != hkey)
2298 RegCloseKey(xhkey);
2299 return ret;
2303 /******************************************************************************
2304 * RegQueryValueEx32A [ADVAPI32.157]
2306 * NOTES:
2307 * the documantation is wrong: if the buffer is to small it remains untouched
2309 * FIXME: check returnvalue (len) for an empty key
2311 DWORD WINAPI RegQueryValueEx32A( HKEY hkey, LPSTR lpszValueName,
2312 LPDWORD lpdwReserved, LPDWORD lpdwType,
2313 LPBYTE lpbData, LPDWORD lpcbData )
2315 LPWSTR lpszValueNameW;
2316 LPBYTE mybuf = NULL;
2317 DWORD ret, mytype, mylen = 0;
2319 TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2320 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2322 if (!lpcbData && lpbData) /* buffer without size is illegal */
2323 { return ERROR_INVALID_PARAMETER;
2326 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2328 /* get just the type first */
2329 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2331 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2332 { if(lpszValueNameW) free(lpszValueNameW);
2333 return ret;
2336 if (lpcbData) /* at least length requested? */
2337 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2338 { if (lpbData ) /* value requested? */
2339 { mylen = 2*( *lpcbData );
2340 mybuf = (LPBYTE)xmalloc( mylen );
2343 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2345 if (ret == ERROR_SUCCESS )
2346 { if ( lpbData )
2347 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2351 *lpcbData = mylen/2; /* size is in byte! */
2353 else /* no strings, call it straight */
2354 { ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2358 if (lpdwType) /* type when requested */
2359 { *lpdwType = mytype;
2362 TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2364 if(mybuf) free(mybuf);
2365 if(lpszValueNameW) free(lpszValueNameW);
2366 return ret;
2370 /******************************************************************************
2371 * RegQueryValueEx16 [KERNEL.225]
2373 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2374 LPDWORD lpdwReserved, LPDWORD lpdwType,
2375 LPBYTE lpbData, LPDWORD lpcbData )
2377 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2378 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2379 return RegQueryValueEx32A( hkey, lpszValueName, lpdwReserved, lpdwType,
2380 lpbData, lpcbData );
2384 /******************************************************************************
2385 * RegQueryValue32A [ADVAPI32.156]
2387 DWORD WINAPI RegQueryValue32A( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2388 LPDWORD lpcbData )
2390 HKEY xhkey;
2391 DWORD ret, dwType;
2393 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2394 lpcbData?*lpcbData:0);
2396 if (lpszSubKey && *lpszSubKey) {
2397 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2398 if( ret != ERROR_SUCCESS )
2399 return ret;
2400 } else
2401 xhkey = hkey;
2403 dwType = REG_SZ;
2404 ret = RegQueryValueEx32A( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2405 lpcbData );
2406 if( xhkey != hkey )
2407 RegCloseKey( xhkey );
2408 return ret;
2412 /******************************************************************************
2413 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2415 * NOTES
2416 * Is this HACK still applicable?
2418 * HACK
2419 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2420 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2421 * Aldus FH4)
2423 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2424 LPDWORD lpcbData )
2426 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2427 lpcbData?*lpcbData:0);
2429 if (lpcbData)
2430 *lpcbData &= 0xFFFF;
2431 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2436 * Setting values of Registry keys
2438 * Callpath:
2439 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2440 * RegSetValue32W -> RegSetValueEx32W
2444 /******************************************************************************
2445 * RegSetValueEx32W [ADVAPI32.170]
2446 * Sets the data and type of a value under a register key
2448 * PARAMS
2449 * hkey [I] Handle of key to set value for
2450 * lpszValueName [I] Name of value to set
2451 * dwReserved [I] Reserved - must be zero
2452 * dwType [I] Flag for value type
2453 * lpbData [I] Address of value data
2454 * cbData [I] Size of value data
2456 * RETURNS
2457 * Success: ERROR_SUCCESS
2458 * Failure: Error code
2460 * NOTES
2461 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2463 DWORD WINAPI RegSetValueEx32W( HKEY hkey, LPWSTR lpszValueName,
2464 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2465 DWORD cbData)
2467 LPKEYSTRUCT lpkey;
2468 int i;
2470 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2471 dwReserved, dwType, lpbData, cbData);
2473 debug_print_value ( lpbData, dwType, cbData );
2475 lpkey = lookup_hkey( hkey );
2477 if (!lpkey)
2478 return ERROR_INVALID_HANDLE;
2480 lpkey->flags |= REG_OPTION_TAINTED;
2482 if (lpszValueName==NULL) {
2483 /* Sets type and name for key's unnamed or default value */
2484 for (i=0;i<lpkey->nrofvalues;i++)
2485 if (lpkey->values[i].name==NULL)
2486 break;
2487 } else {
2488 for (i=0;i<lpkey->nrofvalues;i++)
2489 if ( lpkey->values[i].name &&
2490 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2492 break;
2494 if (i==lpkey->nrofvalues) {
2495 lpkey->values = (LPKEYVALUE)xrealloc(
2496 lpkey->values,
2497 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2499 lpkey->nrofvalues++;
2500 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2502 if (lpkey->values[i].name==NULL) {
2503 if (lpszValueName)
2504 lpkey->values[i].name = strdupW(lpszValueName);
2505 else
2506 lpkey->values[i].name = NULL;
2509 if (dwType == REG_SZ)
2510 cbData = 2 * (lstrlen32W ((LPCWSTR)lpbData) + 1);
2512 lpkey->values[i].len = cbData;
2513 lpkey->values[i].type = dwType;
2514 if (lpkey->values[i].data !=NULL)
2515 free(lpkey->values[i].data);
2516 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2517 lpkey->values[i].lastmodified = time(NULL);
2518 memcpy(lpkey->values[i].data,lpbData,cbData);
2519 return ERROR_SUCCESS;
2523 /******************************************************************************
2524 * RegSetValueEx32A [ADVAPI32.169]
2526 * NOTES
2527 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2529 DWORD WINAPI RegSetValueEx32A( HKEY hkey, LPSTR lpszValueName,
2530 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2531 DWORD cbData )
2533 LPBYTE buf;
2534 LPWSTR lpszValueNameW;
2535 DWORD ret;
2537 if (!lpbData)
2538 return (ERROR_INVALID_PARAMETER);
2540 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2541 dwReserved,dwType,lpbData,cbData);
2543 if ((1<<dwType) & UNICONVMASK)
2544 { if (dwType == REG_SZ)
2545 cbData = strlen ((LPCSTR)lpbData)+1;
2547 buf = (LPBYTE)xmalloc( cbData *2 );
2548 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2549 cbData=2*cbData;
2551 else
2552 buf=lpbData;
2554 if (lpszValueName)
2555 lpszValueNameW = strdupA2W(lpszValueName);
2556 else
2557 lpszValueNameW = NULL;
2559 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2561 if (lpszValueNameW)
2562 free(lpszValueNameW);
2564 if (buf!=lpbData)
2565 free(buf);
2567 return ret;
2571 /******************************************************************************
2572 * RegSetValueEx16 [KERNEL.226]
2574 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2575 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2577 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2578 dwReserved,dwType,lpbData,cbData);
2579 return RegSetValueEx32A( hkey, lpszValueName, dwReserved, dwType, lpbData,
2580 cbData );
2584 /******************************************************************************
2585 * RegSetValue32W [ADVAPI32.171]
2587 DWORD WINAPI RegSetValue32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2588 LPCWSTR lpszData, DWORD cbData )
2590 HKEY xhkey;
2591 DWORD ret;
2593 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2594 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2596 if (lpszSubKey && *lpszSubKey) {
2597 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2598 if (ret!=ERROR_SUCCESS)
2599 return ret;
2600 } else
2601 xhkey=hkey;
2602 if (dwType!=REG_SZ) {
2603 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2604 dwType=REG_SZ;
2606 if (cbData!=2*lstrlen32W(lpszData)+2) {
2607 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2608 cbData,debugstr_w(lpszData),2*lstrlen32W(lpszData)+2
2610 cbData=2*lstrlen32W(lpszData)+2;
2612 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2613 if (hkey!=xhkey)
2614 RegCloseKey(xhkey);
2615 return ret;
2619 /******************************************************************************
2620 * RegSetValue32A [ADVAPI32.168]
2623 DWORD WINAPI RegSetValue32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2624 LPCSTR lpszData, DWORD cbData )
2626 DWORD ret;
2627 HKEY xhkey;
2629 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2630 if (lpszSubKey && *lpszSubKey) {
2631 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2632 if (ret!=ERROR_SUCCESS)
2633 return ret;
2634 } else
2635 xhkey=hkey;
2637 if (dwType!=REG_SZ) {
2638 TRACE(reg,"dwType=%ld!\n",dwType);
2639 dwType=REG_SZ;
2641 if (cbData!=strlen(lpszData)+1)
2642 cbData=strlen(lpszData)+1;
2643 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2644 if (xhkey!=hkey)
2645 RegCloseKey(xhkey);
2646 return ret;
2650 /******************************************************************************
2651 * RegSetValue16 [KERNEL.221] [SHELL.5]
2653 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2654 LPCSTR lpszData, DWORD cbData )
2656 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2657 debugstr_a(lpszData),cbData);
2658 return RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2663 * Key Enumeration
2665 * Callpath:
2666 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2667 * RegEnumKey32W -> RegEnumKeyEx32W
2671 /******************************************************************************
2672 * RegEnumKeyEx32W [ADVAPI32.139]
2674 * PARAMS
2675 * hkey [I] Handle to key to enumerate
2676 * iSubKey [I] Index of subkey to enumerate
2677 * lpszName [O] Buffer for subkey name
2678 * lpcchName [O] Size of subkey buffer
2679 * lpdwReserved [I] Reserved
2680 * lpszClass [O] Buffer for class string
2681 * lpcchClass [O] Size of class buffer
2682 * ft [O] Time key last written to
2684 DWORD WINAPI RegEnumKeyEx32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2685 LPDWORD lpcchName, LPDWORD lpdwReserved,
2686 LPWSTR lpszClass, LPDWORD lpcchClass,
2687 FILETIME *ft )
2689 LPKEYSTRUCT lpkey,lpxkey;
2691 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2692 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2694 lpkey = lookup_hkey( hkey );
2695 if (!lpkey)
2696 return ERROR_INVALID_HANDLE;
2698 if (!lpkey->nextsub)
2699 return ERROR_NO_MORE_ITEMS;
2700 lpxkey=lpkey->nextsub;
2702 /* Traverse the subkeys */
2703 while (iSubkey && lpxkey) {
2704 iSubkey--;
2705 lpxkey=lpxkey->next;
2708 if (iSubkey || !lpxkey)
2709 return ERROR_NO_MORE_ITEMS;
2710 if (lstrlen32W(lpxkey->keyname)+1>*lpcchName)
2711 return ERROR_MORE_DATA;
2712 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2714 if (*lpcchName)
2715 *lpcchName = lstrlen32W(lpszName);
2717 if (lpszClass) {
2718 /* FIXME: what should we write into it? */
2719 *lpszClass = 0;
2720 *lpcchClass = 2;
2722 return ERROR_SUCCESS;
2726 /******************************************************************************
2727 * RegEnumKey32W [ADVAPI32.140]
2729 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2730 DWORD lpcchName )
2732 FILETIME ft;
2734 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2735 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2739 /******************************************************************************
2740 * RegEnumKeyEx32A [ADVAPI32.138]
2742 DWORD WINAPI RegEnumKeyEx32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2743 LPDWORD lpcchName, LPDWORD lpdwReserved,
2744 LPSTR lpszClass, LPDWORD lpcchClass,
2745 FILETIME *ft )
2747 DWORD ret,lpcchNameW,lpcchClassW;
2748 LPWSTR lpszNameW,lpszClassW;
2751 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2752 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2754 if (lpszName) {
2755 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2756 lpcchNameW = *lpcchName;
2757 } else {
2758 lpszNameW = NULL;
2759 lpcchNameW = 0;
2761 if (lpszClass) {
2762 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2763 lpcchClassW = *lpcchClass;
2764 } else {
2765 lpszClassW =0;
2766 lpcchClassW=0;
2768 ret=RegEnumKeyEx32W(
2769 hkey,
2770 iSubkey,
2771 lpszNameW,
2772 &lpcchNameW,
2773 lpdwReserved,
2774 lpszClassW,
2775 &lpcchClassW,
2778 if (ret==ERROR_SUCCESS) {
2779 lstrcpyWtoA(lpszName,lpszNameW);
2780 *lpcchName=strlen(lpszName);
2781 if (lpszClassW) {
2782 lstrcpyWtoA(lpszClass,lpszClassW);
2783 *lpcchClass=strlen(lpszClass);
2786 if (lpszNameW)
2787 free(lpszNameW);
2788 if (lpszClassW)
2789 free(lpszClassW);
2790 return ret;
2794 /******************************************************************************
2795 * RegEnumKey32A [ADVAPI32.137]
2797 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2798 DWORD lpcchName )
2800 FILETIME ft;
2802 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2803 return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
2804 NULL, &ft );
2808 /******************************************************************************
2809 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2811 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2812 DWORD lpcchName )
2814 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2815 return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2820 * Enumerate Registry Values
2822 * Callpath:
2823 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2827 /******************************************************************************
2828 * RegEnumValue32W [ADVAPI32.142]
2830 * PARAMS
2831 * hkey [I] Handle to key to query
2832 * iValue [I] Index of value to query
2833 * lpszValue [O] Value string
2834 * lpcchValue [I/O] Size of value buffer (in wchars)
2835 * lpdReserved [I] Reserved
2836 * lpdwType [O] Type code
2837 * lpbData [O] Value data
2838 * lpcbData [I/O] Size of data buffer (in bytes)
2840 * Note: wide character functions that take and/or return "character counts"
2841 * use TCHAR (that is unsigned short or char) not byte counts.
2843 DWORD WINAPI RegEnumValue32W( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
2844 LPDWORD lpcchValue, LPDWORD lpdReserved,
2845 LPDWORD lpdwType, LPBYTE lpbData,
2846 LPDWORD lpcbData )
2848 LPKEYSTRUCT lpkey;
2849 LPKEYVALUE val;
2851 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
2852 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
2854 lpkey = lookup_hkey( hkey );
2856 if (!lpcbData && lpbData)
2857 return ERROR_INVALID_PARAMETER;
2859 if (!lpkey)
2860 return ERROR_INVALID_HANDLE;
2862 if (lpkey->nrofvalues <= iValue)
2863 return ERROR_NO_MORE_ITEMS;
2865 val = &(lpkey->values[iValue]);
2867 if (val->name) {
2868 if (lstrlen32W(val->name)+1>*lpcchValue) {
2869 *lpcchValue = lstrlen32W(val->name)+1;
2870 return ERROR_MORE_DATA;
2872 memcpy(lpszValue,val->name,2 * (lstrlen32W(val->name)+1) );
2873 *lpcchValue=lstrlen32W(val->name);
2874 } else {
2875 *lpszValue = 0;
2876 *lpcchValue = 0;
2879 /* Can be NULL if the type code is not required */
2880 if (lpdwType)
2881 *lpdwType = val->type;
2883 if (lpbData) {
2884 if (val->len>*lpcbData)
2885 return ERROR_MORE_DATA;
2886 memcpy(lpbData,val->data,val->len);
2887 *lpcbData = val->len;
2890 debug_print_value ( val->data, val->type, val->len );
2891 return ERROR_SUCCESS;
2895 /******************************************************************************
2896 * RegEnumValue32A [ADVAPI32.141]
2898 DWORD WINAPI RegEnumValue32A( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2899 LPDWORD lpcchValue, LPDWORD lpdReserved,
2900 LPDWORD lpdwType, LPBYTE lpbData,
2901 LPDWORD lpcbData )
2903 LPWSTR lpszValueW;
2904 LPBYTE lpbDataW;
2905 DWORD ret,lpcbDataW;
2906 DWORD dwType;
2908 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2909 lpdReserved,lpdwType,lpbData,lpcbData);
2911 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2912 if (lpbData) {
2913 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2914 lpcbDataW = *lpcbData;
2915 } else
2916 lpbDataW = NULL;
2918 ret = RegEnumValue32W( hkey, iValue, lpszValueW, lpcchValue,
2919 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2921 if (lpdwType)
2922 *lpdwType = dwType;
2924 if (ret==ERROR_SUCCESS) {
2925 lstrcpyWtoA(lpszValue,lpszValueW);
2926 if (lpbData) {
2927 if ((1<<dwType) & UNICONVMASK) {
2928 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2929 } else {
2930 if (lpcbDataW > *lpcbData)
2931 ret = ERROR_MORE_DATA;
2932 else
2933 memcpy(lpbData,lpbDataW,lpcbDataW);
2935 *lpcbData = lpcbDataW;
2938 if (lpbDataW) free(lpbDataW);
2939 if (lpszValueW) free(lpszValueW);
2940 return ret;
2944 /******************************************************************************
2945 * RegEnumValue16 [KERNEL.223]
2947 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2948 LPDWORD lpcchValue, LPDWORD lpdReserved,
2949 LPDWORD lpdwType, LPBYTE lpbData,
2950 LPDWORD lpcbData )
2952 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2953 lpdReserved,lpdwType,lpbData,lpcbData);
2954 return RegEnumValue32A( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
2955 lpdwType, lpbData, lpcbData );
2959 /******************************************************************************
2960 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2961 * Releases the handle of the specified key
2963 * PARAMS
2964 * hkey [I] Handle of key to close
2966 * RETURNS
2967 * Success: ERROR_SUCCESS
2968 * Failure: Error code
2970 DWORD WINAPI RegCloseKey( HKEY hkey )
2972 TRACE(reg,"(%x)\n",hkey);
2974 /* The standard handles are allowed to succeed, even though they are not
2975 closed */
2976 if (is_standard_hkey(hkey))
2977 return ERROR_SUCCESS;
2979 return remove_handle(hkey);
2984 * Delete registry key
2986 * Callpath:
2987 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2991 /******************************************************************************
2992 * RegDeleteKey32W [ADVAPI32.134]
2994 * PARAMS
2995 * hkey [I] Handle to open key
2996 * lpszSubKey [I] Name of subkey to delete
2998 * RETURNS
2999 * Success: ERROR_SUCCESS
3000 * Failure: Error code
3002 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
3004 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3005 LPWSTR *wps;
3006 int wpc,i;
3008 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3010 lpNextKey = lookup_hkey(hkey);
3011 if (!lpNextKey)
3012 return ERROR_INVALID_HANDLE;
3014 /* Subkey param cannot be NULL */
3015 if (!lpszSubKey || !*lpszSubKey)
3016 return ERROR_BADKEY;
3018 /* We need to know the previous key in the hier. */
3019 split_keypath(lpszSubKey,&wps,&wpc);
3020 i = 0;
3021 lpxkey = lpNextKey;
3022 while (i<wpc-1) {
3023 lpxkey=lpNextKey->nextsub;
3024 while (lpxkey) {
3025 TRACE(reg, " Scanning [%s]\n",
3026 debugstr_w(lpxkey->keyname));
3027 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
3028 break;
3029 lpxkey=lpxkey->next;
3031 if (!lpxkey) {
3032 FREE_KEY_PATH;
3033 TRACE(reg, " Not found.\n");
3034 /* not found is success */
3035 return ERROR_SUCCESS;
3037 i++;
3038 lpNextKey = lpxkey;
3040 lpxkey = lpNextKey->nextsub;
3041 lplpPrevKey = &(lpNextKey->nextsub);
3042 while (lpxkey) {
3043 TRACE(reg, " Scanning [%s]\n",
3044 debugstr_w(lpxkey->keyname));
3045 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
3046 break;
3047 lplpPrevKey = &(lpxkey->next);
3048 lpxkey = lpxkey->next;
3051 if (!lpxkey) {
3052 FREE_KEY_PATH;
3053 WARN(reg , " Not found.\n");
3054 return ERROR_FILE_NOT_FOUND;
3057 if (lpxkey->nextsub) {
3058 FREE_KEY_PATH;
3059 WARN(reg , " Not empty.\n");
3060 return ERROR_CANTWRITE;
3062 *lplpPrevKey = lpxkey->next;
3063 free(lpxkey->keyname);
3064 if (lpxkey->class)
3065 free(lpxkey->class);
3066 if (lpxkey->values)
3067 free(lpxkey->values);
3068 free(lpxkey);
3069 FREE_KEY_PATH;
3070 TRACE(reg, " Done.\n");
3071 return ERROR_SUCCESS;
3075 /******************************************************************************
3076 * RegDeleteKey32A [ADVAPI32.133]
3078 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
3080 LPWSTR lpszSubKeyW;
3081 DWORD ret;
3083 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3084 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3085 ret = RegDeleteKey32W( hkey, lpszSubKeyW );
3086 if(lpszSubKeyW) free(lpszSubKeyW);
3087 return ret;
3091 /******************************************************************************
3092 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3094 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3096 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3097 return RegDeleteKey32A( hkey, lpszSubKey );
3102 * Delete registry value
3104 * Callpath:
3105 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3109 /******************************************************************************
3110 * RegDeleteValue32W [ADVAPI32.136]
3112 * PARAMS
3113 * hkey [I]
3114 * lpszValue [I]
3116 * RETURNS
3118 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
3120 DWORD i;
3121 LPKEYSTRUCT lpkey;
3122 LPKEYVALUE val;
3124 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3126 lpkey = lookup_hkey( hkey );
3127 if (!lpkey)
3128 return ERROR_INVALID_HANDLE;
3130 if (lpszValue) {
3131 for (i=0;i<lpkey->nrofvalues;i++)
3132 if ( lpkey->values[i].name &&
3133 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3135 break;
3136 } else {
3137 for (i=0;i<lpkey->nrofvalues;i++)
3138 if (lpkey->values[i].name==NULL)
3139 break;
3142 if (i == lpkey->nrofvalues)
3143 return ERROR_FILE_NOT_FOUND;
3145 val = lpkey->values+i;
3146 if (val->name) free(val->name);
3147 if (val->data) free(val->data);
3148 memcpy(
3149 lpkey->values+i,
3150 lpkey->values+i+1,
3151 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3153 lpkey->values = (LPKEYVALUE)xrealloc(
3154 lpkey->values,
3155 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3157 lpkey->nrofvalues--;
3158 return ERROR_SUCCESS;
3162 /******************************************************************************
3163 * RegDeleteValue32A [ADVAPI32.135]
3165 DWORD WINAPI RegDeleteValue32A( HKEY hkey, LPSTR lpszValue )
3167 LPWSTR lpszValueW;
3168 DWORD ret;
3170 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3171 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3172 ret = RegDeleteValue32W( hkey, lpszValueW );
3173 if(lpszValueW) free(lpszValueW);
3174 return ret;
3178 /******************************************************************************
3179 * RegDeleteValue16 [KERNEL.222]
3181 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3183 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3184 return RegDeleteValue32A( hkey, lpszValue );
3188 /******************************************************************************
3189 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3190 * Writes key to registry
3192 * PARAMS
3193 * hkey [I] Handle of key to write
3195 * RETURNS
3196 * Success: ERROR_SUCCESS
3197 * Failure: Error code
3199 DWORD WINAPI RegFlushKey( HKEY hkey )
3201 LPKEYSTRUCT lpkey;
3202 BOOL32 ret;
3204 TRACE(reg, "(%x)\n", hkey);
3206 lpkey = lookup_hkey( hkey );
3207 if (!lpkey)
3208 return ERROR_BADKEY;
3210 ERR(reg, "What is the correct filename?\n");
3212 ret = _savereg( lpkey, "foo.bar", TRUE);
3214 if( ret ) {
3215 return ERROR_SUCCESS;
3216 } else
3217 return ERROR_UNKNOWN; /* FIXME */
3221 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3224 /******************************************************************************
3225 * RegQueryInfoKey32W [ADVAPI32.153]
3227 * PARAMS
3228 * hkey [I] Handle to key to query
3229 * lpszClass [O] Buffer for class string
3230 * lpcchClass [O] Size of class string buffer
3231 * lpdwReserved [I] Reserved
3232 * lpcSubKeys [I] Buffer for number of subkeys
3233 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3234 * lpcchMaxClass [O] Buffer for longest class string length
3235 * lpcValues [O] Buffer for number of value entries
3236 * lpcchMaxValueName [O] Buffer for longest value name length
3237 * lpccbMaxValueData [O] Buffer for longest value data length
3238 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3239 * ft
3240 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3241 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3242 * lpcchClass is NULL
3243 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3244 * (it's hard to test validity, so test !NULL instead)
3246 DWORD WINAPI RegQueryInfoKey32W( HKEY hkey, LPWSTR lpszClass,
3247 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3248 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3249 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3250 LPDWORD lpcchMaxValueName,
3251 LPDWORD lpccbMaxValueData,
3252 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3254 LPKEYSTRUCT lpkey,lpxkey;
3255 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3256 int i;
3258 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3259 lpkey = lookup_hkey(hkey);
3260 if (!lpkey)
3261 return ERROR_INVALID_HANDLE;
3262 if (lpszClass) {
3263 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3264 return ERROR_INVALID_PARAMETER;
3266 /* either lpcchClass is valid or this is win95 and lpcchClass
3267 could be invalid */
3268 if (lpkey->class) {
3269 DWORD classLen = lstrlen32W(lpkey->class);
3271 if (lpcchClass && classLen+1>*lpcchClass) {
3272 *lpcchClass=classLen+1;
3273 return ERROR_MORE_DATA;
3275 if (lpcchClass)
3276 *lpcchClass=classLen;
3277 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3278 } else {
3279 *lpszClass = 0;
3280 if (lpcchClass)
3281 *lpcchClass = 0;
3283 } else {
3284 if (lpcchClass)
3285 *lpcchClass = lstrlen32W(lpkey->class);
3287 lpxkey=lpkey->nextsub;
3288 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3289 while (lpxkey) {
3290 nrofkeys++;
3291 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
3292 maxsubkey=lstrlen32W(lpxkey->keyname);
3293 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
3294 maxclass=lstrlen32W(lpxkey->class);
3295 lpxkey=lpxkey->next;
3297 for (i=0;i<lpkey->nrofvalues;i++) {
3298 LPKEYVALUE val=lpkey->values+i;
3300 if (val->name && lstrlen32W(val->name)>maxvname)
3301 maxvname=lstrlen32W(val->name);
3302 if (val->len>maxvdata)
3303 maxvdata=val->len;
3305 if (!maxclass) maxclass = 1;
3306 if (!maxvname) maxvname = 1;
3307 if (lpcValues)
3308 *lpcValues = lpkey->nrofvalues;
3309 if (lpcSubKeys)
3310 *lpcSubKeys = nrofkeys;
3311 if (lpcchMaxSubkey)
3312 *lpcchMaxSubkey = maxsubkey;
3313 if (lpcchMaxClass)
3314 *lpcchMaxClass = maxclass;
3315 if (lpcchMaxValueName)
3316 *lpcchMaxValueName= maxvname;
3317 if (lpccbMaxValueData)
3318 *lpccbMaxValueData= maxvdata;
3319 return ERROR_SUCCESS;
3323 /******************************************************************************
3324 * RegQueryInfoKey32A [ADVAPI32.152]
3326 DWORD WINAPI RegQueryInfoKey32A( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3327 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3328 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3329 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3330 LPDWORD lpccbMaxValueData,
3331 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3333 LPWSTR lpszClassW = NULL;
3334 DWORD ret;
3336 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3337 if (lpszClass) {
3338 if (lpcchClass) {
3339 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3340 } else if (VERSION_GetVersion() == WIN95) {
3341 /* win95 allows lpcchClass to be null */
3342 /* we don't know how big lpszClass is, would
3343 MAX_PATHNAME_LEN be the correct default? */
3344 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3347 } else
3348 lpszClassW = NULL;
3349 ret=RegQueryInfoKey32W(
3350 hkey,
3351 lpszClassW,
3352 lpcchClass,
3353 lpdwReserved,
3354 lpcSubKeys,
3355 lpcchMaxSubkey,
3356 lpcchMaxClass,
3357 lpcValues,
3358 lpcchMaxValueName,
3359 lpccbMaxValueData,
3360 lpcbSecurityDescriptor,
3363 if (ret==ERROR_SUCCESS && lpszClass)
3364 lstrcpyWtoA(lpszClass,lpszClassW);
3365 if (lpszClassW)
3366 free(lpszClassW);
3367 return ret;
3371 /******************************************************************************
3372 * RegConnectRegistry32W [ADVAPI32.128]
3374 * PARAMS
3375 * lpMachineName [I] Address of name of remote computer
3376 * hHey [I] Predefined registry handle
3377 * phkResult [I] Address of buffer for remote registry handle
3379 LONG WINAPI RegConnectRegistry32W( LPCWSTR lpMachineName, HKEY hKey,
3380 LPHKEY phkResult )
3382 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3384 if (!lpMachineName || !*lpMachineName) {
3385 /* Use the local machine name */
3386 return RegOpenKey16( hKey, "", phkResult );
3389 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3390 return ERROR_BAD_NETPATH;
3394 /******************************************************************************
3395 * RegConnectRegistry32A [ADVAPI32.127]
3397 LONG WINAPI RegConnectRegistry32A( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3399 DWORD ret;
3400 LPWSTR machineW = strdupA2W(machine);
3401 ret = RegConnectRegistry32W( machineW, hkey, reskey );
3402 free(machineW);
3403 return ret;
3407 /******************************************************************************
3408 * RegGetKeySecurity [ADVAPI32.144]
3409 * Retrieves a copy of security descriptor protecting the registry key
3411 * PARAMS
3412 * hkey [I] Open handle of key to set
3413 * SecurityInformation [I] Descriptor contents
3414 * pSecurityDescriptor [O] Address of descriptor for key
3415 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3417 * RETURNS
3418 * Success: ERROR_SUCCESS
3419 * Failure: Error code
3421 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3422 SECURITY_INFORMATION SecurityInformation,
3423 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3424 LPDWORD lpcbSecurityDescriptor )
3426 LPKEYSTRUCT lpkey;
3428 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3429 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3431 lpkey = lookup_hkey( hkey );
3432 if (!lpkey)
3433 return ERROR_INVALID_HANDLE;
3435 /* FIXME: Check for valid SecurityInformation values */
3437 if (*lpcbSecurityDescriptor < sizeof(*pSecurityDescriptor))
3438 return ERROR_INSUFFICIENT_BUFFER;
3440 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3441 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3443 return ERROR_SUCCESS;
3447 /******************************************************************************
3448 * RegLoadKey32W [ADVAPI32.???]
3450 * PARAMS
3451 * hkey [I] Handle of open key
3452 * lpszSubKey [I] Address of name of subkey
3453 * lpszFile [I] Address of filename for registry information
3455 LONG WINAPI RegLoadKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3457 LPKEYSTRUCT lpkey;
3458 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3460 /* Do this check before the hkey check */
3461 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3462 return ERROR_INVALID_PARAMETER;
3464 lpkey = lookup_hkey( hkey );
3465 if (!lpkey)
3466 return ERROR_INVALID_HANDLE;
3468 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3469 debugstr_w(lpszFile));
3471 return ERROR_SUCCESS;
3475 /******************************************************************************
3476 * RegLoadKey32A [ADVAPI32.???]
3478 LONG WINAPI RegLoadKey32A( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3480 LONG ret;
3481 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3482 LPWSTR lpszFileW = strdupA2W(lpszFile);
3483 ret = RegLoadKey32W( hkey, lpszSubKeyW, lpszFileW );
3484 if(lpszFileW) free(lpszFileW);
3485 if(lpszSubKeyW) free(lpszSubKeyW);
3486 return ret;
3490 /******************************************************************************
3491 * RegNotifyChangeKeyValue [ADVAPI32.???]
3493 * PARAMS
3494 * hkey [I] Handle of key to watch
3495 * fWatchSubTree [I] Flag for subkey notification
3496 * fdwNotifyFilter [I] Changes to be reported
3497 * hEvent [I] Handle of signaled event
3498 * fAsync [I] Flag for asynchronous reporting
3500 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL32 fWatchSubTree,
3501 DWORD fdwNotifyFilter, HANDLE32 hEvent,
3502 BOOL32 fAsync )
3504 LPKEYSTRUCT lpkey;
3505 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3506 hEvent,fAsync);
3508 lpkey = lookup_hkey( hkey );
3509 if (!lpkey)
3510 return ERROR_INVALID_HANDLE;
3512 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3513 hEvent,fAsync);
3515 return ERROR_SUCCESS;
3519 /******************************************************************************
3520 * RegUnLoadKey32W [ADVAPI32.173]
3522 * PARAMS
3523 * hkey [I] Handle of open key
3524 * lpSubKey [I] Address of name of subkey to unload
3526 LONG WINAPI RegUnLoadKey32W( HKEY hkey, LPCWSTR lpSubKey )
3528 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3529 return ERROR_SUCCESS;
3533 /******************************************************************************
3534 * RegUnLoadKey32A [ADVAPI32.172]
3536 LONG WINAPI RegUnLoadKey32A( HKEY hkey, LPCSTR lpSubKey )
3538 LONG ret;
3539 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3540 ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3541 if(lpSubKeyW) free(lpSubKeyW);
3542 return ret;
3546 /******************************************************************************
3547 * RegSetKeySecurity [ADVAPI32.167]
3549 * PARAMS
3550 * hkey [I] Open handle of key to set
3551 * SecurityInfo [I] Descriptor contents
3552 * pSecurityDesc [I] Address of descriptor for key
3554 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3555 PSECURITY_DESCRIPTOR pSecurityDesc )
3557 LPKEYSTRUCT lpkey;
3559 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3561 /* It seems to perform this check before the hkey check */
3562 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3563 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3564 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3565 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3566 /* Param OK */
3567 } else
3568 return ERROR_INVALID_PARAMETER;
3570 if (!pSecurityDesc)
3571 return ERROR_INVALID_PARAMETER;
3573 lpkey = lookup_hkey( hkey );
3574 if (!lpkey)
3575 return ERROR_INVALID_HANDLE;
3577 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3579 return ERROR_SUCCESS;
3583 /******************************************************************************
3584 * RegSaveKey32W [ADVAPI32.166]
3586 * PARAMS
3587 * hkey [I] Handle of key where save begins
3588 * lpFile [I] Address of filename to save to
3589 * sa [I] Address of security structure
3591 LONG WINAPI RegSaveKey32W( HKEY hkey, LPCWSTR lpFile,
3592 LPSECURITY_ATTRIBUTES sa )
3594 LPKEYSTRUCT lpkey;
3596 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3598 /* It appears to do this check before the hkey check */
3599 if (!lpFile || !*lpFile)
3600 return ERROR_INVALID_PARAMETER;
3602 lpkey = lookup_hkey( hkey );
3603 if (!lpkey)
3604 return ERROR_INVALID_HANDLE;
3606 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3608 return ERROR_SUCCESS;
3612 /******************************************************************************
3613 * RegSaveKey32A [ADVAPI32.165]
3615 LONG WINAPI RegSaveKey32A( HKEY hkey, LPCSTR lpFile,
3616 LPSECURITY_ATTRIBUTES sa )
3618 LONG ret;
3619 LPWSTR lpFileW = strdupA2W(lpFile);
3620 ret = RegSaveKey32W( hkey, lpFileW, sa );
3621 free(lpFileW);
3622 return ret;
3626 /******************************************************************************
3627 * RegRestoreKey32W [ADVAPI32.164]
3629 * PARAMS
3630 * hkey [I] Handle of key where restore begins
3631 * lpFile [I] Address of filename containing saved tree
3632 * dwFlags [I] Optional flags
3634 LONG WINAPI RegRestoreKey32W( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3636 LPKEYSTRUCT lpkey;
3638 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3640 /* It seems to do this check before the hkey check */
3641 if (!lpFile || !*lpFile)
3642 return ERROR_INVALID_PARAMETER;
3644 lpkey = lookup_hkey( hkey );
3645 if (!lpkey)
3646 return ERROR_INVALID_HANDLE;
3648 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3650 /* Check for file existence */
3652 return ERROR_SUCCESS;
3656 /******************************************************************************
3657 * RegRestoreKey32A [ADVAPI32.163]
3659 LONG WINAPI RegRestoreKey32A( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3661 LONG ret;
3662 LPWSTR lpFileW = strdupA2W(lpFile);
3663 ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3664 if(lpFileW) free(lpFileW);
3665 return ret;
3669 /******************************************************************************
3670 * RegReplaceKey32W [ADVAPI32.162]
3672 * PARAMS
3673 * hkey [I] Handle of open key
3674 * lpSubKey [I] Address of name of subkey
3675 * lpNewFile [I] Address of filename for file with new data
3676 * lpOldFile [I] Address of filename for backup file
3678 LONG WINAPI RegReplaceKey32W( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3679 LPCWSTR lpOldFile )
3681 LPKEYSTRUCT lpkey;
3683 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3684 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3686 lpkey = lookup_hkey( hkey );
3687 if (!lpkey)
3688 return ERROR_INVALID_HANDLE;
3690 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3691 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3693 return ERROR_SUCCESS;
3697 /******************************************************************************
3698 * RegReplaceKey32A [ADVAPI32.161]
3700 LONG WINAPI RegReplaceKey32A( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3701 LPCSTR lpOldFile )
3703 LONG ret;
3704 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3705 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3706 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3707 ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3708 free(lpOldFileW);
3709 free(lpNewFileW);
3710 free(lpSubKeyW);
3711 return ret;