Implemented flag FILE_FLAG_DELETE_ON_CLOSE.
[wine/multimedia.git] / misc / registry.c
blobb738b716d5ca4cbe1a6d3e8173b1a323060e3b7e
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 "windows.h"
34 #include "win.h"
35 #include "winerror.h"
36 #include "file.h"
37 #include "heap.h"
38 #include "debug.h"
39 #include "xmalloc.h"
40 #include "winreg.h"
41 #include "winversion.h"
43 static void REGISTRY_Init(void);
44 /* FIXME: following defines should be configured global ... */
46 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
47 #define WINE_PREFIX "/.wine"
48 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
49 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
51 /* relative in ~user/.wine/ : */
52 #define SAVE_CURRENT_USER "user.reg"
53 #define SAVE_LOCAL_MACHINE "system.reg"
55 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
56 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
58 /* one value of a key */
59 typedef struct tagKEYVALUE
61 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
62 DWORD type; /* type of value */
63 DWORD len; /* length of data in BYTEs */
64 DWORD lastmodified; /* time of seconds since 1.1.1970 */
65 LPBYTE data; /* content, may be strings, binaries, etc. */
66 } KEYVALUE,*LPKEYVALUE;
68 /* a registry key */
69 typedef struct tagKEYSTRUCT
71 LPWSTR keyname; /* name of THIS key (UNICODE) */
72 DWORD flags; /* flags. */
73 LPWSTR class;
74 /* values */
75 DWORD nrofvalues; /* nr of values in THIS key */
76 LPKEYVALUE values; /* values in THIS key */
77 /* key management pointers */
78 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
79 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
80 } KEYSTRUCT, *LPKEYSTRUCT;
83 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
84 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
85 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
86 static KEYSTRUCT *key_users=NULL; /* all users? */
88 /* dynamic, not saved */
89 static KEYSTRUCT *key_performance_data=NULL;
90 static KEYSTRUCT *key_current_config=NULL;
91 static KEYSTRUCT *key_dyn_data=NULL;
93 /* what valuetypes do we need to convert? */
94 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
97 static struct openhandle {
98 LPKEYSTRUCT lpkey;
99 HKEY hkey;
100 REGSAM accessmask;
101 } *openhandles=NULL;
102 static int nrofopenhandles=0;
103 /* Starts after 1 because 0,1 are reserved for Win16 */
104 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
105 HKEYs for remote registry access */
106 static int currenthandle=2;
110 * QUESTION
111 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
112 * If so, can we remove them?
113 * ANSWER
114 * No, the memory handling functions are called very often in here,
115 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
116 * loading 100 times slower. -MM
118 static LPWSTR strdupA2W(LPCSTR src)
120 if(src) {
121 LPWSTR dest=xmalloc(2*strlen(src)+2);
122 lstrcpyAtoW(dest,src);
123 return dest;
125 return NULL;
128 static LPWSTR strdupW(LPCWSTR a) {
129 LPWSTR b;
130 int len;
132 if(a) {
133 len=sizeof(WCHAR)*(lstrlen32W(a)+1);
134 b=(LPWSTR)xmalloc(len);
135 memcpy(b,a,len);
136 return b;
138 return NULL;
141 LPWSTR strcvtA2W(LPCSTR src, int nchars)
144 LPWSTR dest = xmalloc (2 * nchars + 2);
146 lstrcpynAtoW(dest,src,nchars+1);
147 dest[nchars] = 0;
148 return dest;
151 * we need to convert A to W with '\0' in strings (MULTI_SZ)
154 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT32 n )
155 { LPWSTR p = dst;
157 TRACE(reg,"\"%s\" %i\n",src, n);
159 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
161 return dst;
163 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT32 n )
164 { LPSTR p = dst;
166 TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
168 while (n-- > 0) *p++ = (CHAR)*src++;
170 return dst;
173 static void debug_print_value (LPBYTE lpbData, DWORD type, DWORD len)
174 { if (TRACE_ON(reg) && lpbData)
175 { switch(type)
176 { case REG_SZ:
177 TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
178 break;
180 case REG_DWORD:
181 TRACE(reg," Data(dword)=0x%08lx\n",(DWORD)*lpbData);
182 break;
184 case REG_MULTI_SZ:
185 { int i;
186 LPCWSTR ptr = (LPCWSTR)lpbData;
187 for (i=0;ptr[0];i++)
188 { TRACE(reg, " MULTI_SZ(%i=%s)\n", i, debugstr_w(ptr));
189 ptr += lstrlen32W(ptr)+1;
192 break;
194 case REG_BINARY:
195 { char szTemp[100]; /* 3*32 + 3 + 1 */
196 int i;
197 for ( i = 0; i < len ; i++)
198 { sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
199 if (i>=31)
200 { sprintf (&(szTemp[i*3+3]),"...");
201 break;
204 TRACE(reg," Data(raw)=(%s)\n", szTemp);
206 break;
208 default:
209 FIXME(reg, " Unknown data type %ld\n", type);
210 } /* switch */
211 } /* if */
216 /******************************************************************************
217 * is_standard_hkey [Internal]
218 * Determines if a hkey is a standard key
220 static BOOL32 is_standard_hkey( HKEY hkey )
222 switch(hkey) {
223 case 0x00000000:
224 case 0x00000001:
225 case HKEY_CLASSES_ROOT:
226 case HKEY_CURRENT_CONFIG:
227 case HKEY_CURRENT_USER:
228 case HKEY_LOCAL_MACHINE:
229 case HKEY_USERS:
230 case HKEY_PERFORMANCE_DATA:
231 case HKEY_DYN_DATA:
232 return TRUE;
233 default:
234 return FALSE;
238 /******************************************************************************
239 * add_handle [Internal]
241 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
243 int i;
245 TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
246 /* Check for duplicates */
247 for (i=0;i<nrofopenhandles;i++) {
248 if (openhandles[i].lpkey==lpkey) {
249 /* This is not really an error - the user is allowed to create
250 two (or more) handles to the same key */
251 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
253 if (openhandles[i].hkey==hkey) {
254 WARN(reg, "Adding handle %x twice\n",hkey);
257 openhandles=xrealloc( openhandles,
258 sizeof(struct openhandle)*(nrofopenhandles+1));
260 openhandles[i].lpkey = lpkey;
261 openhandles[i].hkey = hkey;
262 openhandles[i].accessmask = accessmask;
263 nrofopenhandles++;
267 /******************************************************************************
268 * get_handle [Internal]
270 * RETURNS
271 * Success: Pointer to key
272 * Failure: NULL
274 static LPKEYSTRUCT get_handle( HKEY hkey )
276 int i;
278 for (i=0; i<nrofopenhandles; i++)
279 if (openhandles[i].hkey == hkey)
280 return openhandles[i].lpkey;
281 WARN(reg, "Could not find handle 0x%x\n",hkey);
282 return NULL;
286 /******************************************************************************
287 * remove_handle [Internal]
289 * PARAMS
290 * hkey [I] Handle of key to remove
292 * RETURNS
293 * Success: ERROR_SUCCESS
294 * Failure: ERROR_INVALID_HANDLE
296 static DWORD remove_handle( HKEY hkey )
298 int i;
300 for (i=0;i<nrofopenhandles;i++)
301 if (openhandles[i].hkey==hkey)
302 break;
304 if (i == nrofopenhandles) {
305 WARN(reg, "Could not find handle 0x%x\n",hkey);
306 return ERROR_INVALID_HANDLE;
309 memcpy( openhandles+i,
310 openhandles+i+1,
311 sizeof(struct openhandle)*(nrofopenhandles-i-1)
313 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
314 nrofopenhandles--;
315 return ERROR_SUCCESS;
318 /******************************************************************************
319 * lookup_hkey [Internal]
321 * Just as the name says. Creates the root keys on demand, so we can call the
322 * Reg* functions at any time.
324 * RETURNS
325 * Success: Pointer to key structure
326 * Failure: NULL
328 #define ADD_ROOT_KEY(xx) \
329 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
330 memset(xx,'\0',sizeof(KEYSTRUCT));\
331 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
333 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
335 switch (hkey) {
336 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
337 * some programs. Do not remove those cases. -MM
339 case 0x00000000:
340 case 0x00000001:
341 case HKEY_CLASSES_ROOT: {
342 if (!key_classes_root) {
343 HKEY cl_r_hkey;
345 /* calls lookup_hkey recursively, TWICE */
346 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
347 ERR(reg,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
348 exit(1);
350 key_classes_root = lookup_hkey(cl_r_hkey);
352 return key_classes_root;
354 case HKEY_CURRENT_USER:
355 if (!key_current_user) {
356 HKEY c_u_hkey;
357 struct passwd *pwd;
359 pwd=getpwuid(getuid());
360 /* calls lookup_hkey recursively, TWICE */
361 if (pwd && pwd->pw_name) {
362 if (RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey)!=ERROR_SUCCESS) {
363 ERR(reg,"Could not create HU\\%s. This is impossible.\n",pwd->pw_name);
364 exit(1);
366 key_current_user = lookup_hkey(c_u_hkey);
367 } else {
368 /* nothing found, use standalone */
369 ADD_ROOT_KEY(key_current_user);
372 return key_current_user;
373 case HKEY_LOCAL_MACHINE:
374 if (!key_local_machine) {
375 ADD_ROOT_KEY(key_local_machine);
376 REGISTRY_Init();
378 return key_local_machine;
379 case HKEY_USERS:
380 if (!key_users) {
381 ADD_ROOT_KEY(key_users);
383 return key_users;
384 case HKEY_PERFORMANCE_DATA:
385 if (!key_performance_data) {
386 ADD_ROOT_KEY(key_performance_data);
388 return key_performance_data;
389 case HKEY_DYN_DATA:
390 if (!key_dyn_data) {
391 ADD_ROOT_KEY(key_dyn_data);
393 return key_dyn_data;
394 case HKEY_CURRENT_CONFIG:
395 if (!key_current_config) {
396 ADD_ROOT_KEY(key_current_config);
398 return key_current_config;
399 default:
400 return get_handle(hkey);
402 /*NOTREACHED*/
404 #undef ADD_ROOT_KEY
405 /* so we don't accidently access them ... */
406 #define key_current_config NULL NULL
407 #define key_current_user NULL NULL
408 #define key_users NULL NULL
409 #define key_local_machine NULL NULL
410 #define key_classes_root NULL NULL
411 #define key_dyn_data NULL NULL
412 #define key_performance_data NULL NULL
414 /******************************************************************************
415 * split_keypath [Internal]
416 * splits the unicode string 'wp' into an array of strings.
417 * the array is allocated by this function.
418 * Free the array using FREE_KEY_PATH
420 * PARAMS
421 * wp [I] String to split up
422 * wpv [O] Array of pointers to strings
423 * wpc [O] Number of components
425 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
427 int i,j,len;
428 LPWSTR ws;
430 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
432 ws = HEAP_strdupW( SystemHeap, 0, wp );
434 /* We know we have at least one substring */
435 *wpc = 1;
437 /* Replace each backslash with NULL, and increment the count */
438 for (i=0;ws[i];i++) {
439 if (ws[i]=='\\') {
440 ws[i]=0;
441 (*wpc)++;
445 len = i;
447 /* Allocate the space for the array of pointers, leaving room for the
448 NULL at the end */
449 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
450 (*wpv)[0]= ws;
452 /* Assign each pointer to the appropriate character in the string */
453 j = 1;
454 for (i=1;i<len;i++)
455 if (ws[i-1]==0) {
456 (*wpv)[j++]=ws+i;
457 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
460 (*wpv)[j]=NULL;
462 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
467 /******************************************************************************
468 * REGISTRY_Init [Internal]
469 * Registry initialisation, allocates some default keys.
471 static void REGISTRY_Init(void) {
472 HKEY hkey;
473 char buf[200];
475 TRACE(reg,"(void)\n");
477 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
478 RegCloseKey(hkey);
480 /* This was an Open, but since it is called before the real registries
481 are loaded, it was changed to a Create - MTB 980507*/
482 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
483 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
484 RegCloseKey(hkey);
486 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
487 * CurrentVersion
488 * CurrentBuildNumber
489 * CurrentType
490 * string RegisteredOwner
491 * string RegisteredOrganization
494 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
495 * string SysContact
496 * string SysLocation
497 * SysServices
499 if (-1!=gethostname(buf,200)) {
500 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
501 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
502 RegCloseKey(hkey);
507 /************************ SAVE Registry Function ****************************/
509 #define REGISTRY_SAVE_VERSION 0x00000001
511 /* Registry saveformat:
512 * If you change it, increase above number by 1, which will flush
513 * old registry database files.
515 * Global:
516 * "WINE REGISTRY Version %d"
517 * subkeys....
518 * Subkeys:
519 * keyname
520 * valuename=lastmodified,type,data
521 * ...
522 * subkeys
523 * ...
524 * keyname,valuename,stringdata:
525 * the usual ascii characters from 0x00-0xff (well, not 0x00)
526 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
527 * ( "=\\\t" escaped in \uXXXX form.)
528 * type,lastmodified:
529 * int
531 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
533 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
534 * SaveOnlyUpdatedKeys=yes
537 /******************************************************************************
538 * _save_check_tainted [Internal]
540 static int _save_check_tainted( LPKEYSTRUCT lpkey )
542 int tainted;
544 if (!lpkey)
545 return 0;
546 if (lpkey->flags & REG_OPTION_TAINTED)
547 tainted = 1;
548 else
549 tainted = 0;
550 while (lpkey) {
551 if (_save_check_tainted(lpkey->nextsub)) {
552 lpkey->flags |= REG_OPTION_TAINTED;
553 tainted = 1;
555 lpkey = lpkey->next;
557 return tainted;
560 /******************************************************************************
561 * _save_USTRING [Internal]
563 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
565 LPWSTR s;
566 int doescape;
568 if (wstr==NULL)
569 return;
570 s=wstr;
571 while (*s) {
572 doescape=0;
573 if (*s>0xff)
574 doescape = 1;
575 if (*s=='\n')
576 doescape = 1;
577 if (escapeeq && *s=='=')
578 doescape = 1;
579 if (*s=='\\')
580 fputc(*s,F); /* if \\ then put it twice. */
581 if (doescape)
582 fprintf(F,"\\u%04x",*((unsigned short*)s));
583 else
584 fputc(*s,F);
585 s++;
589 /******************************************************************************
590 * _savesubkey [Internal]
592 * NOTES
593 * REG_MULTI_SZ is handled as binary (like in win95) (js)
595 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
597 LPKEYSTRUCT lpxkey;
598 int i,tabs,j;
600 lpxkey = lpkey;
601 while (lpxkey) {
602 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
603 (all || (lpxkey->flags & REG_OPTION_TAINTED))
605 for (tabs=level;tabs--;)
606 fputc('\t',F);
607 _save_USTRING(F,lpxkey->keyname,1);
608 fputs("\n",F);
609 for (i=0;i<lpxkey->nrofvalues;i++) {
610 LPKEYVALUE val=lpxkey->values+i;
612 for (tabs=level+1;tabs--;)
613 fputc('\t',F);
614 _save_USTRING(F,val->name,0);
615 fputc('=',F);
616 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
617 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
618 _save_USTRING(F,(LPWSTR)val->data,0);
619 else
620 for (j=0;j<val->len;j++)
621 fprintf(F,"%02x",*((unsigned char*)val->data+j));
622 fputs("\n",F);
624 /* descend recursively */
625 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
626 return 0;
628 lpxkey=lpxkey->next;
630 return 1;
634 /******************************************************************************
635 * _savesubreg [Internal]
637 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
639 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
640 _save_check_tainted(lpkey->nextsub);
641 return _savesubkey(F,lpkey->nextsub,0,all);
645 /******************************************************************************
646 * _savereg [Internal]
648 static BOOL32 _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
650 FILE *F;
652 F=fopen(fn,"w");
653 if (F==NULL) {
654 WARN(reg,"Couldn't open %s for writing: %s\n",
655 fn,strerror(errno)
657 return FALSE;
659 if (!_savesubreg(F,lpkey,all)) {
660 fclose(F);
661 unlink(fn);
662 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
663 return FALSE;
665 fclose(F);
666 return TRUE;
670 /******************************************************************************
671 * SHELL_SaveRegistry [Internal]
673 void SHELL_SaveRegistry( void )
675 char *fn;
676 struct passwd *pwd;
677 char buf[4];
678 HKEY hkey;
679 int all;
681 TRACE(reg,"(void)\n");
683 all=0;
684 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
685 strcpy(buf,"yes");
686 } else {
687 DWORD len,junk,type;
689 len=4;
690 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
691 hkey,
692 VAL_SAVEUPDATED,
693 &junk,
694 &type,
695 buf,
696 &len
697 ))|| (type!=REG_SZ)
699 strcpy(buf,"yes");
700 RegCloseKey(hkey);
702 if (lstrcmpi32A(buf,"yes"))
703 all=1;
704 pwd=getpwuid(getuid());
705 if (pwd!=NULL && pwd->pw_dir!=NULL)
707 char *tmp;
709 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
710 strlen(SAVE_CURRENT_USER) + 2 );
711 strcpy(fn,pwd->pw_dir);
712 strcat(fn,WINE_PREFIX);
713 /* create the directory. don't care about errorcodes. */
714 mkdir(fn,0755); /* drwxr-xr-x */
715 strcat(fn,"/"SAVE_CURRENT_USER);
716 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
717 strcpy(tmp,fn);strcat(tmp,".tmp");
718 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
719 if (-1==rename(tmp,fn)) {
720 perror("rename tmp registry");
721 unlink(tmp);
724 free(tmp);
725 free(fn);
726 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
727 strcpy(fn,pwd->pw_dir);
728 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
729 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
730 strcpy(tmp,fn);strcat(tmp,".tmp");
731 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
732 if (-1==rename(tmp,fn)) {
733 perror("rename tmp registry");
734 unlink(tmp);
737 free(tmp);
738 free(fn);
739 } else
740 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
744 /************************ LOAD Registry Function ****************************/
748 /******************************************************************************
749 * _find_or_add_key [Internal]
751 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
753 LPKEYSTRUCT lpxkey,*lplpkey;
755 if ((!keyname) || (keyname[0]==0)) {
756 free(keyname);
757 return lpkey;
759 lplpkey= &(lpkey->nextsub);
760 lpxkey = *lplpkey;
761 while (lpxkey) {
762 if ( (lpxkey->keyname[0]==keyname[0]) &&
763 !lstrcmpi32W(lpxkey->keyname,keyname)
765 break;
766 lplpkey = &(lpxkey->next);
767 lpxkey = *lplpkey;
769 if (lpxkey==NULL) {
770 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
771 lpxkey = *lplpkey;
772 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
773 lpxkey->keyname = keyname;
774 } else
775 free(keyname);
776 return lpxkey;
779 /******************************************************************************
780 * _find_or_add_value [Internal]
782 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
783 LPBYTE data, DWORD len, DWORD lastmodified )
785 LPKEYVALUE val=NULL;
786 int i;
788 if (name && !*name) {/* empty string equals default (NULL) value */
789 free(name);
790 name = NULL;
793 for (i=0;i<lpkey->nrofvalues;i++) {
794 val=lpkey->values+i;
795 if (name==NULL) {
796 if (val->name==NULL)
797 break;
798 } else {
799 if ( val->name!=NULL &&
800 val->name[0]==name[0] &&
801 !lstrcmpi32W(val->name,name)
803 break;
806 if (i==lpkey->nrofvalues) {
807 lpkey->values = xrealloc(
808 lpkey->values,
809 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
811 val=lpkey->values+i;
812 memset(val,'\0',sizeof(KEYVALUE));
813 val->name = name;
814 } else {
815 if (name)
816 free(name);
818 if (val->lastmodified<lastmodified) {
819 val->lastmodified=lastmodified;
820 val->type = type;
821 val->len = len;
822 if (val->data)
823 free(val->data);
824 val->data = data;
825 } else
826 free(data);
830 /******************************************************************************
831 * _wine_read_line [Internal]
833 * reads a line including dynamically enlarging the readbuffer and throwing
834 * away comments
836 static int _wine_read_line( FILE *F, char **buf, int *len )
838 char *s,*curread;
839 int mylen,curoff;
841 curread = *buf;
842 mylen = *len;
843 **buf = '\0';
844 while (1) {
845 while (1) {
846 s=fgets(curread,mylen,F);
847 if (s==NULL)
848 return 0; /* EOF */
849 if (NULL==(s=strchr(curread,'\n'))) {
850 /* buffer wasn't large enough */
851 curoff = strlen(*buf);
852 *buf = xrealloc(*buf,*len*2);
853 curread = *buf + curoff;
854 mylen = *len; /* we filled up the buffer and
855 * got new '*len' bytes to fill
857 *len = *len * 2;
858 } else {
859 *s='\0';
860 break;
863 /* throw away comments */
864 if (**buf=='#' || **buf==';') {
865 curread = *buf;
866 mylen = *len;
867 continue;
869 if (s) /* got end of line */
870 break;
872 return 1;
876 /******************************************************************************
877 * _wine_read_USTRING [Internal]
879 * converts a char* into a UNICODE string (up to a special char)
880 * and returns the position exactly after that string
882 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
884 char *s;
885 LPWSTR ws;
887 /* read up to "=" or "\0" or "\n" */
888 s = buf;
889 if (*s == '=') {
890 /* empty string is the win3.1 default value(NULL)*/
891 *str = NULL;
892 return s;
894 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
895 ws = *str;
896 while (*s && (*s!='\n') && (*s!='=')) {
897 if (*s!='\\')
898 *ws++=*((unsigned char*)s++);
899 else {
900 s++;
901 if (!*s) {
902 /* Dangling \ ... may only happen if a registry
903 * write was short. FIXME: What do to?
905 break;
907 if (*s=='\\') {
908 *ws++='\\';
909 s++;
910 continue;
912 if (*s!='u') {
913 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
914 *ws++='\\';
915 *ws++=*s++;
916 } else {
917 char xbuf[5];
918 int wc;
920 s++;
921 memcpy(xbuf,s,4);xbuf[4]='\0';
922 if (!sscanf(xbuf,"%x",&wc))
923 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
924 s+=4;
925 *ws++ =(unsigned short)wc;
929 *ws = 0;
930 ws = *str;
931 if (*ws)
932 *str = strdupW(*str);
933 else
934 *str = NULL;
935 free(ws);
936 return s;
940 /******************************************************************************
941 * _wine_loadsubkey [Internal]
943 * NOTES
944 * It seems like this is returning a boolean. Should it?
946 * RETURNS
947 * Success: 1
948 * Failure: 0
950 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
951 int *buflen, DWORD optflag )
953 LPKEYSTRUCT lpxkey;
954 int i;
955 char *s;
956 LPWSTR name;
958 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
959 *buflen, optflag);
961 lpkey->flags |= optflag;
963 /* Good. We already got a line here ... so parse it */
964 lpxkey = NULL;
965 while (1) {
966 i=0;s=*buf;
967 while (*s=='\t') {
968 s++;
969 i++;
971 if (i>level) {
972 if (lpxkey==NULL) {
973 WARN(reg,"Got a subhierarchy without resp. key?\n");
974 return 0;
976 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
977 continue;
980 /* let the caller handle this line */
981 if (i<level || **buf=='\0')
982 return 1;
984 /* it can be: a value or a keyname. Parse the name first */
985 s=_wine_read_USTRING(s,&name);
987 /* switch() default: hack to avoid gotos */
988 switch (0) {
989 default:
990 if (*s=='\0') {
991 lpxkey=_find_or_add_key(lpkey,name);
992 } else {
993 LPBYTE data;
994 int len,lastmodified,type;
996 if (*s!='=') {
997 WARN(reg,"Unexpected character: %c\n",*s);
998 break;
1000 s++;
1001 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1002 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1003 break;
1005 /* skip the 2 , */
1006 s=strchr(s,',');s++;
1007 s=strchr(s,',');s++;
1008 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1009 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1010 if (data)
1011 len = lstrlen32W((LPWSTR)data)*2+2;
1012 else
1013 len = 0;
1014 } else {
1015 len=strlen(s)/2;
1016 data = (LPBYTE)xmalloc(len+1);
1017 for (i=0;i<len;i++) {
1018 data[i]=0;
1019 if (*s>='0' && *s<='9')
1020 data[i]=(*s-'0')<<4;
1021 if (*s>='a' && *s<='f')
1022 data[i]=(*s-'a'+'\xa')<<4;
1023 if (*s>='A' && *s<='F')
1024 data[i]=(*s-'A'+'\xa')<<4;
1025 s++;
1026 if (*s>='0' && *s<='9')
1027 data[i]|=*s-'0';
1028 if (*s>='a' && *s<='f')
1029 data[i]|=*s-'a'+'\xa';
1030 if (*s>='A' && *s<='F')
1031 data[i]|=*s-'A'+'\xa';
1032 s++;
1035 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1038 /* read the next line */
1039 if (!_wine_read_line(F,buf,buflen))
1040 return 1;
1042 return 1;
1046 /******************************************************************************
1047 * _wine_loadsubreg [Internal]
1049 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1051 int ver;
1052 char *buf;
1053 int buflen;
1055 buf=xmalloc(10);buflen=10;
1056 if (!_wine_read_line(F,&buf,&buflen)) {
1057 free(buf);
1058 return 0;
1060 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1061 free(buf);
1062 return 0;
1064 if (ver!=REGISTRY_SAVE_VERSION) {
1065 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1066 free(buf);
1067 return 0;
1069 if (!_wine_read_line(F,&buf,&buflen)) {
1070 free(buf);
1071 return 0;
1073 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1074 free(buf);
1075 return 0;
1077 free(buf);
1078 return 1;
1082 /******************************************************************************
1083 * _wine_loadreg [Internal]
1085 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1087 FILE *F;
1089 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1091 F = fopen(fn,"rb");
1092 if (F==NULL) {
1093 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1094 return;
1096 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1097 fclose(F);
1098 unlink(fn);
1099 return;
1101 fclose(F);
1105 /******************************************************************************
1106 * _copy_registry [Internal]
1108 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1110 LPKEYSTRUCT lpxkey;
1111 int j;
1112 LPKEYVALUE valfrom;
1114 from=from->nextsub;
1115 while (from) {
1116 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1118 for (j=0;j<from->nrofvalues;j++) {
1119 LPWSTR name;
1120 LPBYTE data;
1122 valfrom = from->values+j;
1123 name=valfrom->name;
1124 if (name) name=strdupW(name);
1125 data=(LPBYTE)xmalloc(valfrom->len);
1126 memcpy(data,valfrom->data,valfrom->len);
1128 _find_or_add_value(
1129 lpxkey,
1130 name,
1131 valfrom->type,
1132 data,
1133 valfrom->len,
1134 valfrom->lastmodified
1137 _copy_registry(from,lpxkey);
1138 from = from->next;
1143 /* WINDOWS 95 REGISTRY LOADER */
1145 * Structure of a win95 registry database.
1146 * main header:
1147 * 0 : "CREG" - magic
1148 * 4 : DWORD version
1149 * 8 : DWORD offset_of_RGDB_part
1150 * 0C..0F: ? (someone fill in please)
1151 * 10: WORD number of RGDB blocks
1152 * 12: WORD ?
1153 * 14: WORD always 0000?
1154 * 16: WORD always 0001?
1155 * 18..1F: ? (someone fill in please)
1157 * 20: RGKN_section:
1158 * header:
1159 * 0 : "RGKN" - magic
1160 * 4 : DWORD offset to first RGDB section
1161 * 8 : DWORD offset to the root record
1162 * C..0x1B: ? (fill in)
1163 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1165 * Disk Key Entry Structure:
1166 * 00: DWORD - Free entry indicator(?)
1167 * 04: DWORD - Hash = sum of bytes of keyname
1168 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1169 * 0C: DWORD - disk address of PreviousLevel Key.
1170 * 10: DWORD - disk address of Next Sublevel Key.
1171 * 14: DWORD - disk address of Next Key (on same level).
1172 * DKEP>18: WORD - Nr, Low Significant part.
1173 * 1A: WORD - Nr, High Significant part.
1175 * The disk address always points to the nr part of the previous key entry
1176 * of the referenced key. Don't ask me why, or even if I got this correct
1177 * from staring at 1kg of hexdumps. (DKEP)
1179 * The High significant part of the structure seems to equal the number
1180 * of the RGDB section. The low significant part is a unique ID within
1181 * that RGDB section
1183 * There are two minor corrections to the position of that structure.
1184 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1185 * the DKE reread from there.
1186 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1187 * CPS - I have not experienced the above phenomenon in my registry files
1189 * RGDB_section:
1190 * 00: "RGDB" - magic
1191 * 04: DWORD offset to next RGDB section
1192 * 08: DWORD ?
1193 * 0C: WORD always 000d?
1194 * 0E: WORD RGDB block number
1195 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1196 * 14..1F: ?
1197 * 20.....: disk keys
1199 * disk key:
1200 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1201 * 08: WORD nrLS - low significant part of NR
1202 * 0A: WORD nrHS - high significant part of NR
1203 * 0C: DWORD bytesused - bytes used in this structure.
1204 * 10: WORD name_len - length of name in bytes. without \0
1205 * 12: WORD nr_of_values - number of values.
1206 * 14: char name[name_len] - name string. No \0.
1207 * 14+name_len: disk values
1208 * nextkeyoffset: ... next disk key
1210 * disk value:
1211 * 00: DWORD type - value type (hmm, could be WORD too)
1212 * 04: DWORD - unknown, usually 0
1213 * 08: WORD namelen - length of Name. 0 means name=NULL
1214 * 0C: WORD datalen - length of Data.
1215 * 10: char name[namelen] - name, no \0
1216 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1217 * 10+namelen+datalen: next values or disk key
1219 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1220 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1221 * structure) and reading another RGDB_section.
1222 * repeat until end of file.
1224 * An interesting relationship exists in RGDB_section. The value at offset
1225 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1226 * idea at the moment what this means. (Kevin Cozens)
1228 * FIXME: this description needs some serious help, yes.
1231 struct _w95keyvalue {
1232 unsigned long type;
1233 unsigned short datalen;
1234 char *name;
1235 unsigned char *data;
1236 unsigned long x1;
1237 int lastmodified;
1240 struct _w95key {
1241 char *name;
1242 int nrofvals;
1243 struct _w95keyvalue *values;
1244 struct _w95key *prevlvl;
1245 struct _w95key *nextsub;
1246 struct _w95key *next;
1250 struct _w95_info {
1251 char *rgknbuffer;
1252 int rgknsize;
1253 char *rgdbbuffer;
1254 int rgdbsize;
1255 int depth;
1256 int lastmodified;
1260 /******************************************************************************
1261 * _w95_processKey [Internal]
1263 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1264 int nrLS, int nrMS, struct _w95_info *info )
1267 /* Disk Key Header structure (RGDB part) */
1268 struct dkh {
1269 unsigned long nextkeyoff;
1270 unsigned short nrLS;
1271 unsigned short nrMS;
1272 unsigned long bytesused;
1273 unsigned short keynamelen;
1274 unsigned short values;
1275 unsigned long xx1;
1276 /* keyname */
1277 /* disk key values or nothing */
1279 /* Disk Key Value structure */
1280 struct dkv {
1281 unsigned long type;
1282 unsigned long x1;
1283 unsigned short valnamelen;
1284 unsigned short valdatalen;
1285 /* valname, valdata */
1289 struct dkh dkh;
1290 int bytesread = 0;
1291 char *rgdbdata = info->rgdbbuffer;
1292 int nbytes = info->rgdbsize;
1293 char *curdata = rgdbdata;
1294 char *end = rgdbdata + nbytes;
1295 int off_next_rgdb;
1296 char *next = rgdbdata;
1297 int nrgdb, i;
1298 LPKEYSTRUCT lpxkey;
1300 do {
1301 curdata = next;
1302 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1304 memcpy(&off_next_rgdb,curdata+4,4);
1305 next = curdata + off_next_rgdb;
1306 nrgdb = (int) *((short *)curdata + 7);
1308 } while (nrgdb != nrMS && (next < end));
1310 /* curdata now points to the start of the right RGDB section */
1311 curdata += 0x20;
1313 #define XREAD(whereto,len) \
1314 if ((curdata + len) <end) {\
1315 memcpy(whereto,curdata,len);\
1316 curdata+=len;\
1317 bytesread+=len;\
1320 while (curdata < next) {
1321 struct dkh *xdkh = (struct dkh*)curdata;
1323 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1324 if (xdkh->nrLS == nrLS) {
1325 memcpy(&dkh,xdkh,sizeof(dkh));
1326 curdata += sizeof(dkh);
1327 break;
1329 curdata += xdkh->nextkeyoff;
1332 if (dkh.nrLS != nrLS) return (NULL);
1334 if (nrgdb != dkh.nrMS)
1335 return (NULL);
1337 assert((dkh.keynamelen<2) || curdata[0]);
1338 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1339 curdata += dkh.keynamelen;
1341 for (i=0;i< dkh.values; i++) {
1342 struct dkv dkv;
1343 LPBYTE data;
1344 int len;
1345 LPWSTR name;
1347 XREAD(&dkv,sizeof(dkv));
1349 name = strcvtA2W(curdata, dkv.valnamelen);
1350 curdata += dkv.valnamelen;
1352 if ((1 << dkv.type) & UNICONVMASK) {
1353 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1354 len = 2*(dkv.valdatalen + 1);
1355 } else {
1356 /* I don't think we want to NULL terminate all data */
1357 data = xmalloc(dkv.valdatalen);
1358 memcpy (data, curdata, dkv.valdatalen);
1359 len = dkv.valdatalen;
1362 curdata += dkv.valdatalen;
1364 _find_or_add_value(
1365 lpxkey,
1366 name,
1367 dkv.type,
1368 data,
1369 len,
1370 info->lastmodified
1373 return (lpxkey);
1376 /******************************************************************************
1377 * _w95_walkrgkn [Internal]
1379 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1380 struct _w95_info *info )
1383 /* Disk Key Entry structure (RGKN part) */
1384 struct dke {
1385 unsigned long x1;
1386 unsigned long x2;
1387 unsigned long x3;/*usually 0xFFFFFFFF */
1388 unsigned long prevlvl;
1389 unsigned long nextsub;
1390 unsigned long next;
1391 unsigned short nrLS;
1392 unsigned short nrMS;
1393 } *dke = (struct dke *)off;
1394 LPKEYSTRUCT lpxkey;
1396 if (dke == NULL) {
1397 dke = (struct dke *) ((char *)info->rgknbuffer);
1400 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1401 /* XXX <-- This is a hack*/
1402 if (!lpxkey) {
1403 lpxkey = prevkey;
1406 if (dke->nextsub != -1 &&
1407 ((dke->nextsub - 0x20) < info->rgknsize)
1408 && (dke->nextsub > 0x20)) {
1410 _w95_walkrgkn(lpxkey,
1411 info->rgknbuffer + dke->nextsub - 0x20,
1412 info);
1415 if (dke->next != -1 &&
1416 ((dke->next - 0x20) < info->rgknsize) &&
1417 (dke->next > 0x20)) {
1418 _w95_walkrgkn(prevkey,
1419 info->rgknbuffer + dke->next - 0x20,
1420 info);
1423 return;
1427 /******************************************************************************
1428 * _w95_loadreg [Internal]
1430 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1432 HFILE32 hfd;
1433 char magic[5];
1434 unsigned long where,version,rgdbsection,end;
1435 struct _w95_info info;
1436 OFSTRUCT ofs;
1437 BY_HANDLE_FILE_INFORMATION hfdinfo;
1439 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1440 hfd=OpenFile32(fn,&ofs,OF_READ);
1441 if (hfd==HFILE_ERROR32)
1442 return;
1443 magic[4]=0;
1444 if (4!=_lread32(hfd,magic,4))
1445 return;
1446 if (strcmp(magic,"CREG")) {
1447 WARN(reg,"%s is not a w95 registry.\n",fn);
1448 return;
1450 if (4!=_lread32(hfd,&version,4))
1451 return;
1452 if (4!=_lread32(hfd,&rgdbsection,4))
1453 return;
1454 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1455 return;
1456 if (4!=_lread32(hfd,magic,4))
1457 return;
1458 if (strcmp(magic,"RGKN")) {
1459 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1460 return;
1463 /* STEP 1: Keylink structures */
1464 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1465 return;
1466 where = 0x40;
1467 end = rgdbsection;
1469 info.rgknsize = end - where;
1470 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1471 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1472 return;
1474 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1475 return;
1477 end = hfdinfo.nFileSizeLow;
1478 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1480 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1481 return;
1483 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1484 info.rgdbsize = end - rgdbsection;
1486 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1487 return;
1488 _lclose32(hfd);
1490 _w95_walkrgkn(lpkey, NULL, &info);
1492 free (info.rgdbbuffer);
1493 free (info.rgknbuffer);
1497 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1500 reghack - windows 3.11 registry data format demo program.
1502 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1503 a combined hash table and tree description, and finally a text table.
1505 The header is obvious from the struct header. The taboff1 and taboff2
1506 fields are always 0x20, and their usage is unknown.
1508 The 8-byte entry table has various entry types.
1510 tabent[0] is a root index. The second word has the index of the root of
1511 the directory.
1512 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1513 the index of the key/value that has that hash. Data with the same
1514 hash value are on a circular list. The other three words in the
1515 hash entry are always zero.
1516 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1517 entry: dirent and keyent/valent. They are identified by context.
1518 tabent[freeidx] is the first free entry. The first word in a free entry
1519 is the index of the next free entry. The last has 0 as a link.
1520 The other three words in the free list are probably irrelevant.
1522 Entries in text table are preceeded by a word at offset-2. This word
1523 has the value (2*index)+1, where index is the referring keyent/valent
1524 entry in the table. I have no suggestion for the 2* and the +1.
1525 Following the word, there are N bytes of data, as per the keyent/valent
1526 entry length. The offset of the keyent/valent entry is from the start
1527 of the text table to the first data byte.
1529 This information is not available from Microsoft. The data format is
1530 deduced from the reg.dat file by me. Mistakes may
1531 have been made. I claim no rights and give no guarantees for this program.
1533 Tor Sjøwall, tor@sn.no
1536 /* reg.dat header format */
1537 struct _w31_header {
1538 char cookie[8]; /* 'SHCC3.10' */
1539 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1540 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1541 unsigned long tabcnt; /* number of entries in index table */
1542 unsigned long textoff; /* offset of text part */
1543 unsigned long textsize; /* byte size of text part */
1544 unsigned short hashsize; /* hash size */
1545 unsigned short freeidx; /* free index */
1548 /* generic format of table entries */
1549 struct _w31_tabent {
1550 unsigned short w0, w1, w2, w3;
1553 /* directory tabent: */
1554 struct _w31_dirent {
1555 unsigned short sibling_idx; /* table index of sibling dirent */
1556 unsigned short child_idx; /* table index of child dirent */
1557 unsigned short key_idx; /* table index of key keyent */
1558 unsigned short value_idx; /* table index of value valent */
1561 /* key tabent: */
1562 struct _w31_keyent {
1563 unsigned short hash_idx; /* hash chain index for string */
1564 unsigned short refcnt; /* reference count */
1565 unsigned short length; /* length of string */
1566 unsigned short string_off; /* offset of string in text table */
1569 /* value tabent: */
1570 struct _w31_valent {
1571 unsigned short hash_idx; /* hash chain index for string */
1572 unsigned short refcnt; /* reference count */
1573 unsigned short length; /* length of string */
1574 unsigned short string_off; /* offset of string in text table */
1577 /* recursive helper function to display a directory tree */
1578 void
1579 __w31_dumptree( unsigned short idx,
1580 unsigned char *txt,
1581 struct _w31_tabent *tab,
1582 struct _w31_header *head,
1583 LPKEYSTRUCT lpkey,
1584 time_t lastmodified,
1585 int level
1587 struct _w31_dirent *dir;
1588 struct _w31_keyent *key;
1589 struct _w31_valent *val;
1590 LPKEYSTRUCT xlpkey = NULL;
1591 LPWSTR name,value;
1592 static char tail[400];
1594 while (idx!=0) {
1595 dir=(struct _w31_dirent*)&tab[idx];
1597 if (dir->key_idx) {
1598 key = (struct _w31_keyent*)&tab[dir->key_idx];
1600 memcpy(tail,&txt[key->string_off],key->length);
1601 tail[key->length]='\0';
1602 /* all toplevel entries AND the entries in the
1603 * toplevel subdirectory belong to \SOFTWARE\Classes
1605 if (!level && !lstrcmp32A(tail,".classes")) {
1606 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1607 idx=dir->sibling_idx;
1608 continue;
1610 name=strdupA2W(tail);
1612 xlpkey=_find_or_add_key(lpkey,name);
1614 /* only add if leaf node or valued node */
1615 if (dir->value_idx!=0||dir->child_idx==0) {
1616 if (dir->value_idx) {
1617 val=(struct _w31_valent*)&tab[dir->value_idx];
1618 memcpy(tail,&txt[val->string_off],val->length);
1619 tail[val->length]='\0';
1620 value=strdupA2W(tail);
1621 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1624 } else {
1625 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1627 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1628 idx=dir->sibling_idx;
1633 /******************************************************************************
1634 * _w31_loadreg [Internal]
1636 void _w31_loadreg(void) {
1637 HFILE32 hf;
1638 struct _w31_header head;
1639 struct _w31_tabent *tab;
1640 unsigned char *txt;
1641 int len;
1642 OFSTRUCT ofs;
1643 BY_HANDLE_FILE_INFORMATION hfinfo;
1644 time_t lastmodified;
1645 LPKEYSTRUCT lpkey;
1647 TRACE(reg,"(void)\n");
1649 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1650 if (hf==HFILE_ERROR32)
1651 return;
1653 /* read & dump header */
1654 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1655 ERR(reg, "reg.dat is too short.\n");
1656 _lclose32(hf);
1657 return;
1659 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1660 ERR(reg, "reg.dat has bad signature.\n");
1661 _lclose32(hf);
1662 return;
1665 len = head.tabcnt * sizeof(struct _w31_tabent);
1666 /* read and dump index table */
1667 tab = xmalloc(len);
1668 if (len!=_lread32(hf,tab,len)) {
1669 ERR(reg,"couldn't read %d bytes.\n",len);
1670 free(tab);
1671 _lclose32(hf);
1672 return;
1675 /* read text */
1676 txt = xmalloc(head.textsize);
1677 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1678 ERR(reg,"couldn't seek to textblock.\n");
1679 free(tab);
1680 free(txt);
1681 _lclose32(hf);
1682 return;
1684 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1685 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1686 free(tab);
1687 free(txt);
1688 _lclose32(hf);
1689 return;
1692 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1693 ERR(reg,"GetFileInformationByHandle failed?.\n");
1694 free(tab);
1695 free(txt);
1696 _lclose32(hf);
1697 return;
1699 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1700 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1701 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1702 free(tab);
1703 free(txt);
1704 _lclose32(hf);
1705 return;
1709 /**********************************************************************************
1710 * SHELL_LoadRegistry [Internal]
1712 void SHELL_LoadRegistry( void )
1714 char *fn;
1715 struct passwd *pwd;
1716 LPKEYSTRUCT lpkey;
1717 HKEY hkey;
1719 TRACE(reg,"(void)\n");
1721 /* Load windows 3.1 entries */
1722 _w31_loadreg();
1723 /* Load windows 95 entries */
1724 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE));
1725 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE));
1726 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS));
1728 /* the global user default is loaded under HKEY_USERS\\.Default */
1729 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1730 lpkey = lookup_hkey(hkey);
1731 if(!lpkey)
1732 WARN(reg,"Could not create global user default key\n");
1733 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1735 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1736 _copy_registry(lpkey,lookup_hkey(HKEY_CURRENT_USER));
1737 RegCloseKey(hkey);
1739 /* the global machine defaults */
1740 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),SAVE_LOCAL_MACHINE_DEFAULT,0);
1742 /* load the user saved registries */
1744 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1746 pwd=getpwuid(getuid());
1747 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1748 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1749 strcpy(fn,pwd->pw_dir);
1750 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1751 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,REG_OPTION_TAINTED);
1752 free(fn);
1753 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1754 strcpy(fn,pwd->pw_dir);
1755 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1756 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),fn,REG_OPTION_TAINTED);
1757 free(fn);
1758 } else
1759 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1760 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1761 DWORD junk,type,len;
1762 char data[5];
1764 len=4;
1765 if (( RegQueryValueEx32A(
1766 hkey,
1767 VAL_SAVEUPDATED,
1768 &junk,
1769 &type,
1770 data,
1771 &len
1772 )!=ERROR_SUCCESS) ||
1773 type != REG_SZ
1775 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1776 RegCloseKey(hkey);
1781 /********************* API FUNCTIONS ***************************************/
1783 * Open Keys.
1785 * All functions are stubs to RegOpenKeyEx32W where all the
1786 * magic happens.
1788 * Callpath:
1789 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1790 * RegOpenKey32W -> RegOpenKeyEx32W
1794 /******************************************************************************
1795 * RegOpenKeyEx32W [ADVAPI32.150]
1796 * Opens the specified key
1798 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1800 * PARAMS
1801 * hkey [I] Handle of open key
1802 * lpszSubKey [I] Name of subkey to open
1803 * dwReserved [I] Reserved - must be zero
1804 * samDesired [I] Security access mask
1805 * retkey [O] Address of handle of open key
1807 * RETURNS
1808 * Success: ERROR_SUCCESS
1809 * Failure: Error code
1811 DWORD WINAPI RegOpenKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
1812 REGSAM samDesired, LPHKEY retkey )
1814 LPKEYSTRUCT lpNextKey,lpxkey;
1815 LPWSTR *wps;
1816 int wpc,i;
1818 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1819 samDesired,retkey);
1821 lpNextKey = lookup_hkey( hkey );
1822 if (!lpNextKey)
1823 return ERROR_INVALID_HANDLE;
1825 if (!lpszSubKey || !*lpszSubKey) {
1826 /* Either NULL or pointer to empty string, so return a new handle
1827 to the original hkey */
1828 currenthandle += 2;
1829 add_handle(currenthandle,lpNextKey,samDesired);
1830 *retkey=currenthandle;
1831 return ERROR_SUCCESS;
1834 if (lpszSubKey[0] == '\\') {
1835 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1836 return ERROR_BAD_PATHNAME;
1839 split_keypath(lpszSubKey,&wps,&wpc);
1840 i = 0;
1841 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1842 lpxkey = lpNextKey;
1844 while (wps[i]) {
1845 lpxkey=lpNextKey->nextsub;
1846 while (lpxkey) {
1847 if (!lstrcmpi32W(wps[i],lpxkey->keyname)) {
1848 break;
1850 lpxkey=lpxkey->next;
1853 if (!lpxkey) {
1854 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1855 FREE_KEY_PATH;
1856 return ERROR_FILE_NOT_FOUND;
1858 i++;
1859 lpNextKey = lpxkey;
1862 currenthandle += 2;
1863 add_handle(currenthandle,lpxkey,samDesired);
1864 *retkey = currenthandle;
1865 TRACE(reg," Returning %x\n", currenthandle);
1866 FREE_KEY_PATH;
1867 return ERROR_SUCCESS;
1871 /******************************************************************************
1872 * RegOpenKeyEx32A [ADVAPI32.149]
1874 DWORD WINAPI RegOpenKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1875 REGSAM samDesired, LPHKEY retkey )
1877 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1878 DWORD ret;
1880 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1881 samDesired,retkey);
1882 ret = RegOpenKeyEx32W( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
1883 free(lpszSubKeyW);
1884 return ret;
1888 /******************************************************************************
1889 * RegOpenKey32W [ADVAPI32.151]
1891 * PARAMS
1892 * hkey [I] Handle of open key
1893 * lpszSubKey [I] Address of name of subkey to open
1894 * retkey [O] Address of handle of open key
1896 * RETURNS
1897 * Success: ERROR_SUCCESS
1898 * Failure: Error code
1900 DWORD WINAPI RegOpenKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1902 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
1903 return RegOpenKeyEx32W( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1907 /******************************************************************************
1908 * RegOpenKey32A [ADVAPI32.148]
1910 DWORD WINAPI RegOpenKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1912 DWORD ret;
1913 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1914 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1915 ret = RegOpenKey32W( hkey, lpszSubKeyW, retkey );
1916 free(lpszSubKeyW);
1917 return ret;
1921 /******************************************************************************
1922 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1924 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1926 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1927 return RegOpenKey32A( hkey, lpszSubKey, retkey );
1932 * Create keys
1934 * All those functions convert their respective
1935 * arguments and call RegCreateKeyExW at the end.
1937 * We stay away from the Ex functions as long as possible because there are
1938 * differences in the return values
1940 * Callpath:
1941 * RegCreateKeyEx32A \
1942 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1946 /******************************************************************************
1947 * RegCreateKeyEx32W [ADVAPI32.131]
1949 * PARAMS
1950 * hkey [I] Handle of an open key
1951 * lpszSubKey [I] Address of subkey name
1952 * dwReserved [I] Reserved - must be 0
1953 * lpszClass [I] Address of class string
1954 * fdwOptions [I] Special options flag
1955 * samDesired [I] Desired security access
1956 * lpSecAttribs [I] Address of key security structure
1957 * retkey [O] Address of buffer for opened handle
1958 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1960 DWORD WINAPI RegCreateKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey,
1961 DWORD dwReserved, LPWSTR lpszClass,
1962 DWORD fdwOptions, REGSAM samDesired,
1963 LPSECURITY_ATTRIBUTES lpSecAttribs,
1964 LPHKEY retkey, LPDWORD lpDispos )
1966 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1967 LPWSTR *wps;
1968 int wpc,i;
1970 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
1971 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
1972 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
1974 lpNextKey = lookup_hkey(hkey);
1975 if (!lpNextKey)
1976 return ERROR_INVALID_HANDLE;
1978 /* Check for valid options */
1979 switch(fdwOptions) {
1980 case REG_OPTION_NON_VOLATILE:
1981 case REG_OPTION_VOLATILE:
1982 case REG_OPTION_BACKUP_RESTORE:
1983 break;
1984 default:
1985 return ERROR_INVALID_PARAMETER;
1988 /* Sam has to be a combination of the following */
1989 if (!(samDesired &
1990 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
1991 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
1992 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
1993 return ERROR_INVALID_PARAMETER;
1995 if (!lpszSubKey || !*lpszSubKey) {
1996 currenthandle += 2;
1997 add_handle(currenthandle,lpNextKey,samDesired);
1998 *retkey=currenthandle;
1999 TRACE(reg, "Returning %x\n", currenthandle);
2000 lpNextKey->flags|=REG_OPTION_TAINTED;
2001 return ERROR_SUCCESS;
2004 if (lpszSubKey[0] == '\\') {
2005 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2006 return ERROR_BAD_PATHNAME;
2009 split_keypath(lpszSubKey,&wps,&wpc);
2010 i = 0;
2011 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2012 lpxkey = lpNextKey;
2013 while (wps[i]) {
2014 lpxkey=lpNextKey->nextsub;
2015 while (lpxkey) {
2016 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2017 break;
2018 lpxkey=lpxkey->next;
2020 if (!lpxkey)
2021 break;
2022 i++;
2023 lpNextKey = lpxkey;
2025 if (lpxkey) {
2026 currenthandle += 2;
2027 add_handle(currenthandle,lpxkey,samDesired);
2028 lpxkey->flags |= REG_OPTION_TAINTED;
2029 *retkey = currenthandle;
2030 TRACE(reg, "Returning %x\n", currenthandle);
2031 if (lpDispos)
2032 *lpDispos = REG_OPENED_EXISTING_KEY;
2033 FREE_KEY_PATH;
2034 return ERROR_SUCCESS;
2037 /* Good. Now the hard part */
2038 while (wps[i]) {
2039 lplpPrevKey = &(lpNextKey->nextsub);
2040 lpxkey = *lplpPrevKey;
2041 while (lpxkey) {
2042 lplpPrevKey = &(lpxkey->next);
2043 lpxkey = *lplpPrevKey;
2045 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2046 if (!*lplpPrevKey) {
2047 FREE_KEY_PATH;
2048 TRACE(reg, "Returning OUTOFMEMORY\n");
2049 return ERROR_OUTOFMEMORY;
2051 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2052 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2053 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2054 (*lplpPrevKey)->next = NULL;
2055 (*lplpPrevKey)->nextsub = NULL;
2056 (*lplpPrevKey)->values = NULL;
2057 (*lplpPrevKey)->nrofvalues = 0;
2058 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2059 if (lpszClass)
2060 (*lplpPrevKey)->class = strdupW(lpszClass);
2061 else
2062 (*lplpPrevKey)->class = NULL;
2063 lpNextKey = *lplpPrevKey;
2064 i++;
2066 currenthandle += 2;
2067 add_handle(currenthandle,lpNextKey,samDesired);
2069 /*FIXME: flag handling correct? */
2070 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2071 if (lpszClass)
2072 lpNextKey->class = strdupW(lpszClass);
2073 else
2074 lpNextKey->class = NULL;
2075 *retkey = currenthandle;
2076 TRACE(reg, "Returning %x\n", currenthandle);
2077 if (lpDispos)
2078 *lpDispos = REG_CREATED_NEW_KEY;
2079 FREE_KEY_PATH;
2080 return ERROR_SUCCESS;
2084 /******************************************************************************
2085 * RegCreateKeyEx32A [ADVAPI32.130]
2087 DWORD WINAPI RegCreateKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2088 LPSTR lpszClass, DWORD fdwOptions,
2089 REGSAM samDesired,
2090 LPSECURITY_ATTRIBUTES lpSecAttribs,
2091 LPHKEY retkey, LPDWORD lpDispos )
2093 LPWSTR lpszSubKeyW, lpszClassW;
2094 DWORD ret;
2096 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2097 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2098 retkey,lpDispos);
2100 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2101 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2103 ret = RegCreateKeyEx32W( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2104 fdwOptions, samDesired, lpSecAttribs, retkey,
2105 lpDispos );
2107 if(lpszSubKeyW) free(lpszSubKeyW);
2108 if(lpszClassW) free(lpszClassW);
2110 return ret;
2114 /******************************************************************************
2115 * RegCreateKey32W [ADVAPI32.132]
2117 DWORD WINAPI RegCreateKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2119 DWORD junk;
2120 LPKEYSTRUCT lpNextKey;
2122 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2124 /* This check is here because the return value is different than the
2125 one from the Ex functions */
2126 lpNextKey = lookup_hkey(hkey);
2127 if (!lpNextKey)
2128 return ERROR_BADKEY;
2130 return RegCreateKeyEx32W( hkey, lpszSubKey, 0, NULL,
2131 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2132 retkey, &junk);
2136 /******************************************************************************
2137 * RegCreateKey32A [ADVAPI32.129]
2139 DWORD WINAPI RegCreateKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2141 DWORD ret;
2142 LPWSTR lpszSubKeyW;
2144 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2145 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2146 ret = RegCreateKey32W( hkey, lpszSubKeyW, retkey );
2147 if(lpszSubKeyW) free(lpszSubKeyW);
2148 return ret;
2152 /******************************************************************************
2153 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2155 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2157 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2158 return RegCreateKey32A( hkey, lpszSubKey, retkey );
2163 * Query Value Functions
2164 * Win32 differs between keynames and valuenames.
2165 * multiple values may belong to one key, the special value
2166 * with name NULL is the default value used by the win31
2167 * compat functions.
2169 * Callpath:
2170 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2171 * RegQueryValue32W -> RegQueryValueEx32W
2175 /******************************************************************************
2176 * RegQueryValueEx32W [ADVAPI32.158]
2177 * Retrieves type and data for a specified name associated with an open key
2179 * PARAMS
2180 * hkey [I] Handle of key to query
2181 * lpValueName [I] Name of value to query
2182 * lpdwReserved [I] Reserved - must be NULL
2183 * lpdwType [O] Address of buffer for value type. If NULL, the type
2184 * is not required.
2185 * lpbData [O] Address of data buffer. If NULL, the actual data is
2186 * not required.
2187 * lpcbData [I/O] Address of data buffer size
2189 * RETURNS
2190 * ERROR_SUCCESS: Success
2191 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2192 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2194 DWORD WINAPI RegQueryValueEx32W( HKEY hkey, LPWSTR lpValueName,
2195 LPDWORD lpdwReserved, LPDWORD lpdwType,
2196 LPBYTE lpbData, LPDWORD lpcbData )
2198 LPKEYSTRUCT lpkey;
2199 int i;
2200 DWORD ret;
2202 TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2203 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2205 lpkey = lookup_hkey(hkey);
2207 if (!lpkey)
2208 return ERROR_INVALID_HANDLE;
2210 if ((lpbData && ! lpcbData) || lpdwReserved)
2211 return ERROR_INVALID_PARAMETER;
2213 /* An empty name string is equivalent to NULL */
2214 if (lpValueName && !*lpValueName)
2215 lpValueName = NULL;
2217 if (lpValueName==NULL)
2218 { /* Use key's unnamed or default value, if any */
2219 for (i=0;i<lpkey->nrofvalues;i++)
2220 if (lpkey->values[i].name==NULL)
2221 break;
2223 else
2224 { /* Search for the key name */
2225 for (i=0;i<lpkey->nrofvalues;i++)
2226 if ( lpkey->values[i].name && !lstrcmpi32W(lpValueName,lpkey->values[i].name))
2227 break;
2230 if (i==lpkey->nrofvalues)
2231 { TRACE(reg," Key not found\n");
2232 if (lpValueName==NULL)
2233 { /* Empty keyname not found */
2234 if (lpbData)
2235 { *(WCHAR*)lpbData = 0;
2236 *lpcbData = 2;
2238 if (lpdwType)
2239 *lpdwType = REG_SZ;
2240 TRACE(reg, " Returning an empty string\n");
2241 return ERROR_SUCCESS;
2243 return ERROR_FILE_NOT_FOUND;
2246 ret = ERROR_SUCCESS;
2248 if (lpdwType) /* type required ?*/
2249 *lpdwType = lpkey->values[i].type;
2251 if (lpbData) /* data required ?*/
2252 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2253 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2254 else
2255 ret = ERROR_MORE_DATA;
2258 if (lpcbData) /* size required ?*/
2259 { *lpcbData = lpkey->values[i].len;
2262 debug_print_value ( lpbData, lpkey->values[i].type, lpkey->values[i].len);
2264 TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2266 return ret;
2270 /******************************************************************************
2271 * RegQueryValue32W [ADVAPI32.159]
2273 DWORD WINAPI RegQueryValue32W( HKEY hkey, LPWSTR lpszSubKey, LPWSTR lpszData,
2274 LPDWORD lpcbData )
2276 HKEY xhkey;
2277 DWORD ret,lpdwType;
2279 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2280 lpcbData?*lpcbData:0);
2282 /* Only open subkey, if we really do descend */
2283 if (lpszSubKey && *lpszSubKey) {
2284 ret = RegOpenKey32W( hkey, lpszSubKey, &xhkey );
2285 if (ret != ERROR_SUCCESS) {
2286 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2287 return ret;
2289 } else
2290 xhkey = hkey;
2292 lpdwType = REG_SZ;
2293 ret = RegQueryValueEx32W( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2294 lpcbData );
2295 if (xhkey != hkey)
2296 RegCloseKey(xhkey);
2297 return ret;
2301 /******************************************************************************
2302 * RegQueryValueEx32A [ADVAPI32.157]
2304 * NOTES:
2305 * the documantation is wrong: if the buffer is to small it remains untouched
2307 * FIXME: check returnvalue (len) for an empty key
2309 DWORD WINAPI RegQueryValueEx32A( HKEY hkey, LPSTR lpszValueName,
2310 LPDWORD lpdwReserved, LPDWORD lpdwType,
2311 LPBYTE lpbData, LPDWORD lpcbData )
2313 LPWSTR lpszValueNameW;
2314 LPBYTE mybuf = NULL;
2315 DWORD ret, mytype, mylen = 0;
2317 TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2318 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2320 if (!lpcbData && lpbData) /* buffer without size is illegal */
2321 { return ERROR_INVALID_PARAMETER;
2324 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2326 /* get just the type first */
2327 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2329 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2330 { if(lpszValueNameW) free(lpszValueNameW);
2331 return ret;
2334 if (lpcbData) /* at least length requested? */
2335 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2336 { if (lpbData ) /* value requested? */
2337 { mylen = 2*( *lpcbData );
2338 mybuf = (LPBYTE)xmalloc( mylen );
2341 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2343 if (ret == ERROR_SUCCESS )
2344 { if ( lpbData )
2345 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2349 *lpcbData = mylen/2; /* size is in byte! */
2351 else /* no strings, call it straight */
2352 { ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2356 if (lpdwType) /* type when requested */
2357 { *lpdwType = mytype;
2360 TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2362 if(mybuf) free(mybuf);
2363 if(lpszValueNameW) free(lpszValueNameW);
2364 return ret;
2368 /******************************************************************************
2369 * RegQueryValueEx16 [KERNEL.225]
2371 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2372 LPDWORD lpdwReserved, LPDWORD lpdwType,
2373 LPBYTE lpbData, LPDWORD lpcbData )
2375 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2376 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2377 return RegQueryValueEx32A( hkey, lpszValueName, lpdwReserved, lpdwType,
2378 lpbData, lpcbData );
2382 /******************************************************************************
2383 * RegQueryValue32A [ADVAPI32.156]
2385 DWORD WINAPI RegQueryValue32A( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2386 LPDWORD lpcbData )
2388 HKEY xhkey;
2389 DWORD ret, dwType;
2391 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2392 lpcbData?*lpcbData:0);
2394 if (lpszSubKey && *lpszSubKey) {
2395 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2396 if( ret != ERROR_SUCCESS )
2397 return ret;
2398 } else
2399 xhkey = hkey;
2401 dwType = REG_SZ;
2402 ret = RegQueryValueEx32A( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2403 lpcbData );
2404 if( xhkey != hkey )
2405 RegCloseKey( xhkey );
2406 return ret;
2410 /******************************************************************************
2411 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2413 * NOTES
2414 * Is this HACK still applicable?
2416 * HACK
2417 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2418 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2419 * Aldus FH4)
2421 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2422 LPDWORD lpcbData )
2424 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2425 lpcbData?*lpcbData:0);
2427 if (lpcbData)
2428 *lpcbData &= 0xFFFF;
2429 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2434 * Setting values of Registry keys
2436 * Callpath:
2437 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2438 * RegSetValue32W -> RegSetValueEx32W
2442 /******************************************************************************
2443 * RegSetValueEx32W [ADVAPI32.170]
2444 * Sets the data and type of a value under a register key
2446 * PARAMS
2447 * hkey [I] Handle of key to set value for
2448 * lpszValueName [I] Name of value to set
2449 * dwReserved [I] Reserved - must be zero
2450 * dwType [I] Flag for value type
2451 * lpbData [I] Address of value data
2452 * cbData [I] Size of value data
2454 * RETURNS
2455 * Success: ERROR_SUCCESS
2456 * Failure: Error code
2458 * NOTES
2459 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2461 DWORD WINAPI RegSetValueEx32W( HKEY hkey, LPWSTR lpszValueName,
2462 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2463 DWORD cbData)
2465 LPKEYSTRUCT lpkey;
2466 int i;
2468 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2469 dwReserved, dwType, lpbData, cbData);
2471 debug_print_value ( lpbData, dwType, cbData );
2473 lpkey = lookup_hkey( hkey );
2475 if (!lpkey)
2476 return ERROR_INVALID_HANDLE;
2478 lpkey->flags |= REG_OPTION_TAINTED;
2480 if (lpszValueName==NULL) {
2481 /* Sets type and name for key's unnamed or default value */
2482 for (i=0;i<lpkey->nrofvalues;i++)
2483 if (lpkey->values[i].name==NULL)
2484 break;
2485 } else {
2486 for (i=0;i<lpkey->nrofvalues;i++)
2487 if ( lpkey->values[i].name &&
2488 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2490 break;
2492 if (i==lpkey->nrofvalues) {
2493 lpkey->values = (LPKEYVALUE)xrealloc(
2494 lpkey->values,
2495 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2497 lpkey->nrofvalues++;
2498 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2500 if (lpkey->values[i].name==NULL) {
2501 if (lpszValueName)
2502 lpkey->values[i].name = strdupW(lpszValueName);
2503 else
2504 lpkey->values[i].name = NULL;
2507 if (dwType == REG_SZ)
2508 cbData = 2 * (lstrlen32W ((LPCWSTR)lpbData) + 1);
2510 lpkey->values[i].len = cbData;
2511 lpkey->values[i].type = dwType;
2512 if (lpkey->values[i].data !=NULL)
2513 free(lpkey->values[i].data);
2514 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2515 lpkey->values[i].lastmodified = time(NULL);
2516 memcpy(lpkey->values[i].data,lpbData,cbData);
2517 return ERROR_SUCCESS;
2521 /******************************************************************************
2522 * RegSetValueEx32A [ADVAPI32.169]
2524 * NOTES
2525 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2527 DWORD WINAPI RegSetValueEx32A( HKEY hkey, LPSTR lpszValueName,
2528 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2529 DWORD cbData )
2531 LPBYTE buf;
2532 LPWSTR lpszValueNameW;
2533 DWORD ret;
2535 if (!lpbData)
2536 return (ERROR_INVALID_PARAMETER);
2538 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2539 dwReserved,dwType,lpbData,cbData);
2541 if ((1<<dwType) & UNICONVMASK)
2542 { if (dwType == REG_SZ)
2543 cbData = strlen ((LPCSTR)lpbData)+1;
2545 buf = (LPBYTE)xmalloc( cbData *2 );
2546 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2547 cbData=2*cbData;
2549 else
2550 buf=lpbData;
2552 if (lpszValueName)
2553 lpszValueNameW = strdupA2W(lpszValueName);
2554 else
2555 lpszValueNameW = NULL;
2557 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2559 if (lpszValueNameW)
2560 free(lpszValueNameW);
2562 if (buf!=lpbData)
2563 free(buf);
2565 return ret;
2569 /******************************************************************************
2570 * RegSetValueEx16 [KERNEL.226]
2572 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2573 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2575 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2576 dwReserved,dwType,lpbData,cbData);
2577 return RegSetValueEx32A( hkey, lpszValueName, dwReserved, dwType, lpbData,
2578 cbData );
2582 /******************************************************************************
2583 * RegSetValue32W [ADVAPI32.171]
2585 DWORD WINAPI RegSetValue32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2586 LPCWSTR lpszData, DWORD cbData )
2588 HKEY xhkey;
2589 DWORD ret;
2591 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2592 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2594 if (lpszSubKey && *lpszSubKey) {
2595 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2596 if (ret!=ERROR_SUCCESS)
2597 return ret;
2598 } else
2599 xhkey=hkey;
2600 if (dwType!=REG_SZ) {
2601 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2602 dwType=REG_SZ;
2604 if (cbData!=2*lstrlen32W(lpszData)+2) {
2605 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2606 cbData,debugstr_w(lpszData),2*lstrlen32W(lpszData)+2
2608 cbData=2*lstrlen32W(lpszData)+2;
2610 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2611 if (hkey!=xhkey)
2612 RegCloseKey(xhkey);
2613 return ret;
2617 /******************************************************************************
2618 * RegSetValue32A [ADVAPI32.168]
2621 DWORD WINAPI RegSetValue32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2622 LPCSTR lpszData, DWORD cbData )
2624 DWORD ret;
2625 HKEY xhkey;
2627 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2628 if (lpszSubKey && *lpszSubKey) {
2629 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2630 if (ret!=ERROR_SUCCESS)
2631 return ret;
2632 } else
2633 xhkey=hkey;
2635 if (dwType!=REG_SZ) {
2636 TRACE(reg,"dwType=%ld!\n",dwType);
2637 dwType=REG_SZ;
2639 if (cbData!=strlen(lpszData)+1)
2640 cbData=strlen(lpszData)+1;
2641 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2642 if (xhkey!=hkey)
2643 RegCloseKey(xhkey);
2644 return ret;
2648 /******************************************************************************
2649 * RegSetValue16 [KERNEL.221] [SHELL.5]
2651 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2652 LPCSTR lpszData, DWORD cbData )
2654 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2655 debugstr_a(lpszData),cbData);
2656 return RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2661 * Key Enumeration
2663 * Callpath:
2664 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2665 * RegEnumKey32W -> RegEnumKeyEx32W
2669 /******************************************************************************
2670 * RegEnumKeyEx32W [ADVAPI32.139]
2672 * PARAMS
2673 * hkey [I] Handle to key to enumerate
2674 * iSubKey [I] Index of subkey to enumerate
2675 * lpszName [O] Buffer for subkey name
2676 * lpcchName [O] Size of subkey buffer
2677 * lpdwReserved [I] Reserved
2678 * lpszClass [O] Buffer for class string
2679 * lpcchClass [O] Size of class buffer
2680 * ft [O] Time key last written to
2682 DWORD WINAPI RegEnumKeyEx32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2683 LPDWORD lpcchName, LPDWORD lpdwReserved,
2684 LPWSTR lpszClass, LPDWORD lpcchClass,
2685 FILETIME *ft )
2687 LPKEYSTRUCT lpkey,lpxkey;
2689 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2690 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2692 lpkey = lookup_hkey( hkey );
2693 if (!lpkey)
2694 return ERROR_INVALID_HANDLE;
2696 if (!lpkey->nextsub)
2697 return ERROR_NO_MORE_ITEMS;
2698 lpxkey=lpkey->nextsub;
2700 /* Traverse the subkeys */
2701 while (iSubkey && lpxkey) {
2702 iSubkey--;
2703 lpxkey=lpxkey->next;
2706 if (iSubkey || !lpxkey)
2707 return ERROR_NO_MORE_ITEMS;
2708 if (lstrlen32W(lpxkey->keyname)+1>*lpcchName)
2709 return ERROR_MORE_DATA;
2710 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2712 if (*lpcchName)
2713 *lpcchName = lstrlen32W(lpszName);
2715 if (lpszClass) {
2716 /* FIXME: what should we write into it? */
2717 *lpszClass = 0;
2718 *lpcchClass = 2;
2720 return ERROR_SUCCESS;
2724 /******************************************************************************
2725 * RegEnumKey32W [ADVAPI32.140]
2727 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2728 DWORD lpcchName )
2730 FILETIME ft;
2732 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2733 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2737 /******************************************************************************
2738 * RegEnumKeyEx32A [ADVAPI32.138]
2740 DWORD WINAPI RegEnumKeyEx32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2741 LPDWORD lpcchName, LPDWORD lpdwReserved,
2742 LPSTR lpszClass, LPDWORD lpcchClass,
2743 FILETIME *ft )
2745 DWORD ret,lpcchNameW,lpcchClassW;
2746 LPWSTR lpszNameW,lpszClassW;
2749 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2750 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2752 if (lpszName) {
2753 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2754 lpcchNameW = *lpcchName;
2755 } else {
2756 lpszNameW = NULL;
2757 lpcchNameW = 0;
2759 if (lpszClass) {
2760 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2761 lpcchClassW = *lpcchClass;
2762 } else {
2763 lpszClassW =0;
2764 lpcchClassW=0;
2766 ret=RegEnumKeyEx32W(
2767 hkey,
2768 iSubkey,
2769 lpszNameW,
2770 &lpcchNameW,
2771 lpdwReserved,
2772 lpszClassW,
2773 &lpcchClassW,
2776 if (ret==ERROR_SUCCESS) {
2777 lstrcpyWtoA(lpszName,lpszNameW);
2778 *lpcchName=strlen(lpszName);
2779 if (lpszClassW) {
2780 lstrcpyWtoA(lpszClass,lpszClassW);
2781 *lpcchClass=strlen(lpszClass);
2784 if (lpszNameW)
2785 free(lpszNameW);
2786 if (lpszClassW)
2787 free(lpszClassW);
2788 return ret;
2792 /******************************************************************************
2793 * RegEnumKey32A [ADVAPI32.137]
2795 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2796 DWORD lpcchName )
2798 FILETIME ft;
2800 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2801 return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
2802 NULL, &ft );
2806 /******************************************************************************
2807 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2809 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2810 DWORD lpcchName )
2812 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2813 return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2818 * Enumerate Registry Values
2820 * Callpath:
2821 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2825 /******************************************************************************
2826 * RegEnumValue32W [ADVAPI32.142]
2828 * PARAMS
2829 * hkey [I] Handle to key to query
2830 * iValue [I] Index of value to query
2831 * lpszValue [O] Value string
2832 * lpcchValue [I/O] Size of value buffer (in wchars)
2833 * lpdReserved [I] Reserved
2834 * lpdwType [O] Type code
2835 * lpbData [O] Value data
2836 * lpcbData [I/O] Size of data buffer (in bytes)
2838 * Note: wide character functions that take and/or return "character counts"
2839 * use TCHAR (that is unsigned short or char) not byte counts.
2841 DWORD WINAPI RegEnumValue32W( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
2842 LPDWORD lpcchValue, LPDWORD lpdReserved,
2843 LPDWORD lpdwType, LPBYTE lpbData,
2844 LPDWORD lpcbData )
2846 LPKEYSTRUCT lpkey;
2847 LPKEYVALUE val;
2849 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
2850 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
2852 lpkey = lookup_hkey( hkey );
2854 if (!lpcbData && lpbData)
2855 return ERROR_INVALID_PARAMETER;
2857 if (!lpkey)
2858 return ERROR_INVALID_HANDLE;
2860 if (lpkey->nrofvalues <= iValue)
2861 return ERROR_NO_MORE_ITEMS;
2863 val = &(lpkey->values[iValue]);
2865 if (val->name) {
2866 if (lstrlen32W(val->name)+1>*lpcchValue) {
2867 *lpcchValue = lstrlen32W(val->name)+1;
2868 return ERROR_MORE_DATA;
2870 memcpy(lpszValue,val->name,2 * (lstrlen32W(val->name)+1) );
2871 *lpcchValue=lstrlen32W(val->name);
2872 } else {
2873 *lpszValue = 0;
2874 *lpcchValue = 0;
2877 /* Can be NULL if the type code is not required */
2878 if (lpdwType)
2879 *lpdwType = val->type;
2881 if (lpbData) {
2882 if (val->len>*lpcbData)
2883 return ERROR_MORE_DATA;
2884 memcpy(lpbData,val->data,val->len);
2885 *lpcbData = val->len;
2888 debug_print_value ( val->data, val->type, val->len );
2889 return ERROR_SUCCESS;
2893 /******************************************************************************
2894 * RegEnumValue32A [ADVAPI32.141]
2896 DWORD WINAPI RegEnumValue32A( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2897 LPDWORD lpcchValue, LPDWORD lpdReserved,
2898 LPDWORD lpdwType, LPBYTE lpbData,
2899 LPDWORD lpcbData )
2901 LPWSTR lpszValueW;
2902 LPBYTE lpbDataW;
2903 DWORD ret,lpcbDataW;
2904 DWORD dwType;
2906 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2907 lpdReserved,lpdwType,lpbData,lpcbData);
2909 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2910 if (lpbData) {
2911 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2912 lpcbDataW = *lpcbData;
2913 } else
2914 lpbDataW = NULL;
2916 ret = RegEnumValue32W( hkey, iValue, lpszValueW, lpcchValue,
2917 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2919 if (lpdwType)
2920 *lpdwType = dwType;
2922 if (ret==ERROR_SUCCESS) {
2923 lstrcpyWtoA(lpszValue,lpszValueW);
2924 if (lpbData) {
2925 if ((1<<dwType) & UNICONVMASK) {
2926 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2927 } else {
2928 if (lpcbDataW > *lpcbData)
2929 ret = ERROR_MORE_DATA;
2930 else
2931 memcpy(lpbData,lpbDataW,lpcbDataW);
2933 *lpcbData = lpcbDataW;
2936 if (lpbDataW) free(lpbDataW);
2937 if (lpszValueW) free(lpszValueW);
2938 return ret;
2942 /******************************************************************************
2943 * RegEnumValue16 [KERNEL.223]
2945 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2946 LPDWORD lpcchValue, LPDWORD lpdReserved,
2947 LPDWORD lpdwType, LPBYTE lpbData,
2948 LPDWORD lpcbData )
2950 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2951 lpdReserved,lpdwType,lpbData,lpcbData);
2952 return RegEnumValue32A( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
2953 lpdwType, lpbData, lpcbData );
2957 /******************************************************************************
2958 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2959 * Releases the handle of the specified key
2961 * PARAMS
2962 * hkey [I] Handle of key to close
2964 * RETURNS
2965 * Success: ERROR_SUCCESS
2966 * Failure: Error code
2968 DWORD WINAPI RegCloseKey( HKEY hkey )
2970 TRACE(reg,"(%x)\n",hkey);
2972 /* The standard handles are allowed to succeed, even though they are not
2973 closed */
2974 if (is_standard_hkey(hkey))
2975 return ERROR_SUCCESS;
2977 return remove_handle(hkey);
2982 * Delete registry key
2984 * Callpath:
2985 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2989 /******************************************************************************
2990 * RegDeleteKey32W [ADVAPI32.134]
2992 * PARAMS
2993 * hkey [I] Handle to open key
2994 * lpszSubKey [I] Name of subkey to delete
2996 * RETURNS
2997 * Success: ERROR_SUCCESS
2998 * Failure: Error code
3000 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
3002 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3003 LPWSTR *wps;
3004 int wpc,i;
3006 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3008 lpNextKey = lookup_hkey(hkey);
3009 if (!lpNextKey)
3010 return ERROR_INVALID_HANDLE;
3012 /* Subkey param cannot be NULL */
3013 if (!lpszSubKey || !*lpszSubKey)
3014 return ERROR_BADKEY;
3016 /* We need to know the previous key in the hier. */
3017 split_keypath(lpszSubKey,&wps,&wpc);
3018 i = 0;
3019 lpxkey = lpNextKey;
3020 while (i<wpc-1) {
3021 lpxkey=lpNextKey->nextsub;
3022 while (lpxkey) {
3023 TRACE(reg, " Scanning [%s]\n",
3024 debugstr_w(lpxkey->keyname));
3025 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
3026 break;
3027 lpxkey=lpxkey->next;
3029 if (!lpxkey) {
3030 FREE_KEY_PATH;
3031 TRACE(reg, " Not found.\n");
3032 /* not found is success */
3033 return ERROR_SUCCESS;
3035 i++;
3036 lpNextKey = lpxkey;
3038 lpxkey = lpNextKey->nextsub;
3039 lplpPrevKey = &(lpNextKey->nextsub);
3040 while (lpxkey) {
3041 TRACE(reg, " Scanning [%s]\n",
3042 debugstr_w(lpxkey->keyname));
3043 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
3044 break;
3045 lplpPrevKey = &(lpxkey->next);
3046 lpxkey = lpxkey->next;
3049 if (!lpxkey) {
3050 FREE_KEY_PATH;
3051 WARN(reg , " Not found.\n");
3052 return ERROR_FILE_NOT_FOUND;
3055 if (lpxkey->nextsub) {
3056 FREE_KEY_PATH;
3057 WARN(reg , " Not empty.\n");
3058 return ERROR_CANTWRITE;
3060 *lplpPrevKey = lpxkey->next;
3061 free(lpxkey->keyname);
3062 if (lpxkey->class)
3063 free(lpxkey->class);
3064 if (lpxkey->values)
3065 free(lpxkey->values);
3066 free(lpxkey);
3067 FREE_KEY_PATH;
3068 TRACE(reg, " Done.\n");
3069 return ERROR_SUCCESS;
3073 /******************************************************************************
3074 * RegDeleteKey32A [ADVAPI32.133]
3076 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
3078 LPWSTR lpszSubKeyW;
3079 DWORD ret;
3081 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3082 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3083 ret = RegDeleteKey32W( hkey, lpszSubKeyW );
3084 if(lpszSubKeyW) free(lpszSubKeyW);
3085 return ret;
3089 /******************************************************************************
3090 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3092 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3094 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3095 return RegDeleteKey32A( hkey, lpszSubKey );
3100 * Delete registry value
3102 * Callpath:
3103 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3107 /******************************************************************************
3108 * RegDeleteValue32W [ADVAPI32.136]
3110 * PARAMS
3111 * hkey [I]
3112 * lpszValue [I]
3114 * RETURNS
3116 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
3118 DWORD i;
3119 LPKEYSTRUCT lpkey;
3120 LPKEYVALUE val;
3122 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3124 lpkey = lookup_hkey( hkey );
3125 if (!lpkey)
3126 return ERROR_INVALID_HANDLE;
3128 if (lpszValue) {
3129 for (i=0;i<lpkey->nrofvalues;i++)
3130 if ( lpkey->values[i].name &&
3131 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3133 break;
3134 } else {
3135 for (i=0;i<lpkey->nrofvalues;i++)
3136 if (lpkey->values[i].name==NULL)
3137 break;
3140 if (i == lpkey->nrofvalues)
3141 return ERROR_FILE_NOT_FOUND;
3143 val = lpkey->values+i;
3144 if (val->name) free(val->name);
3145 if (val->data) free(val->data);
3146 memcpy(
3147 lpkey->values+i,
3148 lpkey->values+i+1,
3149 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3151 lpkey->values = (LPKEYVALUE)xrealloc(
3152 lpkey->values,
3153 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3155 lpkey->nrofvalues--;
3156 return ERROR_SUCCESS;
3160 /******************************************************************************
3161 * RegDeleteValue32A [ADVAPI32.135]
3163 DWORD WINAPI RegDeleteValue32A( HKEY hkey, LPSTR lpszValue )
3165 LPWSTR lpszValueW;
3166 DWORD ret;
3168 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3169 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3170 ret = RegDeleteValue32W( hkey, lpszValueW );
3171 if(lpszValueW) free(lpszValueW);
3172 return ret;
3176 /******************************************************************************
3177 * RegDeleteValue16 [KERNEL.222]
3179 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3181 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3182 return RegDeleteValue32A( hkey, lpszValue );
3186 /******************************************************************************
3187 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3188 * Writes key to registry
3190 * PARAMS
3191 * hkey [I] Handle of key to write
3193 * RETURNS
3194 * Success: ERROR_SUCCESS
3195 * Failure: Error code
3197 DWORD WINAPI RegFlushKey( HKEY hkey )
3199 LPKEYSTRUCT lpkey;
3200 BOOL32 ret;
3202 TRACE(reg, "(%x)\n", hkey);
3204 lpkey = lookup_hkey( hkey );
3205 if (!lpkey)
3206 return ERROR_BADKEY;
3208 ERR(reg, "What is the correct filename?\n");
3210 ret = _savereg( lpkey, "foo.bar", TRUE);
3212 if( ret ) {
3213 return ERROR_SUCCESS;
3214 } else
3215 return ERROR_UNKNOWN; /* FIXME */
3219 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3222 /******************************************************************************
3223 * RegQueryInfoKey32W [ADVAPI32.153]
3225 * PARAMS
3226 * hkey [I] Handle to key to query
3227 * lpszClass [O] Buffer for class string
3228 * lpcchClass [O] Size of class string buffer
3229 * lpdwReserved [I] Reserved
3230 * lpcSubKeys [I] Buffer for number of subkeys
3231 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3232 * lpcchMaxClass [O] Buffer for longest class string length
3233 * lpcValues [O] Buffer for number of value entries
3234 * lpcchMaxValueName [O] Buffer for longest value name length
3235 * lpccbMaxValueData [O] Buffer for longest value data length
3236 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3237 * ft
3238 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3239 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3240 * lpcchClass is NULL
3241 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3242 * (it's hard to test validity, so test !NULL instead)
3244 DWORD WINAPI RegQueryInfoKey32W( HKEY hkey, LPWSTR lpszClass,
3245 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3246 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3247 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3248 LPDWORD lpcchMaxValueName,
3249 LPDWORD lpccbMaxValueData,
3250 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3252 LPKEYSTRUCT lpkey,lpxkey;
3253 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3254 int i;
3256 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3257 lpkey = lookup_hkey(hkey);
3258 if (!lpkey)
3259 return ERROR_INVALID_HANDLE;
3260 if (lpszClass) {
3261 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3262 return ERROR_INVALID_PARAMETER;
3264 /* either lpcchClass is valid or this is win95 and lpcchClass
3265 could be invalid */
3266 if (lpkey->class) {
3267 DWORD classLen = lstrlen32W(lpkey->class);
3269 if (lpcchClass && classLen+1>*lpcchClass) {
3270 *lpcchClass=classLen+1;
3271 return ERROR_MORE_DATA;
3273 if (lpcchClass)
3274 *lpcchClass=classLen;
3275 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3276 } else {
3277 *lpszClass = 0;
3278 if (lpcchClass)
3279 *lpcchClass = 0;
3281 } else {
3282 if (lpcchClass)
3283 *lpcchClass = lstrlen32W(lpkey->class);
3285 lpxkey=lpkey->nextsub;
3286 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3287 while (lpxkey) {
3288 nrofkeys++;
3289 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
3290 maxsubkey=lstrlen32W(lpxkey->keyname);
3291 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
3292 maxclass=lstrlen32W(lpxkey->class);
3293 lpxkey=lpxkey->next;
3295 for (i=0;i<lpkey->nrofvalues;i++) {
3296 LPKEYVALUE val=lpkey->values+i;
3298 if (val->name && lstrlen32W(val->name)>maxvname)
3299 maxvname=lstrlen32W(val->name);
3300 if (val->len>maxvdata)
3301 maxvdata=val->len;
3303 if (!maxclass) maxclass = 1;
3304 if (!maxvname) maxvname = 1;
3305 if (lpcValues)
3306 *lpcValues = lpkey->nrofvalues;
3307 if (lpcSubKeys)
3308 *lpcSubKeys = nrofkeys;
3309 if (lpcchMaxSubkey)
3310 *lpcchMaxSubkey = maxsubkey;
3311 if (lpcchMaxClass)
3312 *lpcchMaxClass = maxclass;
3313 if (lpcchMaxValueName)
3314 *lpcchMaxValueName= maxvname;
3315 if (lpccbMaxValueData)
3316 *lpccbMaxValueData= maxvdata;
3317 return ERROR_SUCCESS;
3321 /******************************************************************************
3322 * RegQueryInfoKey32A [ADVAPI32.152]
3324 DWORD WINAPI RegQueryInfoKey32A( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3325 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3326 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3327 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3328 LPDWORD lpccbMaxValueData,
3329 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3331 LPWSTR lpszClassW = NULL;
3332 DWORD ret;
3334 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3335 if (lpszClass) {
3336 if (lpcchClass) {
3337 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3338 } else if (VERSION_GetVersion() == WIN95) {
3339 /* win95 allows lpcchClass to be null */
3340 /* we don't know how big lpszClass is, would
3341 MAX_PATHNAME_LEN be the correct default? */
3342 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3345 } else
3346 lpszClassW = NULL;
3347 ret=RegQueryInfoKey32W(
3348 hkey,
3349 lpszClassW,
3350 lpcchClass,
3351 lpdwReserved,
3352 lpcSubKeys,
3353 lpcchMaxSubkey,
3354 lpcchMaxClass,
3355 lpcValues,
3356 lpcchMaxValueName,
3357 lpccbMaxValueData,
3358 lpcbSecurityDescriptor,
3361 if (ret==ERROR_SUCCESS && lpszClass)
3362 lstrcpyWtoA(lpszClass,lpszClassW);
3363 if (lpszClassW)
3364 free(lpszClassW);
3365 return ret;
3369 /******************************************************************************
3370 * RegConnectRegistry32W [ADVAPI32.128]
3372 * PARAMS
3373 * lpMachineName [I] Address of name of remote computer
3374 * hHey [I] Predefined registry handle
3375 * phkResult [I] Address of buffer for remote registry handle
3377 LONG WINAPI RegConnectRegistry32W( LPCWSTR lpMachineName, HKEY hKey,
3378 LPHKEY phkResult )
3380 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3382 if (!lpMachineName || !*lpMachineName) {
3383 /* Use the local machine name */
3384 return RegOpenKey16( hKey, "", phkResult );
3387 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3388 return ERROR_BAD_NETPATH;
3392 /******************************************************************************
3393 * RegConnectRegistry32A [ADVAPI32.127]
3395 LONG WINAPI RegConnectRegistry32A( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3397 DWORD ret;
3398 LPWSTR machineW = strdupA2W(machine);
3399 ret = RegConnectRegistry32W( machineW, hkey, reskey );
3400 free(machineW);
3401 return ret;
3405 /******************************************************************************
3406 * RegGetKeySecurity [ADVAPI32.144]
3407 * Retrieves a copy of security descriptor protecting the registry key
3409 * PARAMS
3410 * hkey [I] Open handle of key to set
3411 * SecurityInformation [I] Descriptor contents
3412 * pSecurityDescriptor [O] Address of descriptor for key
3413 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3415 * RETURNS
3416 * Success: ERROR_SUCCESS
3417 * Failure: Error code
3419 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3420 SECURITY_INFORMATION SecurityInformation,
3421 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3422 LPDWORD lpcbSecurityDescriptor )
3424 LPKEYSTRUCT lpkey;
3426 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3427 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3429 lpkey = lookup_hkey( hkey );
3430 if (!lpkey)
3431 return ERROR_INVALID_HANDLE;
3433 /* FIXME: Check for valid SecurityInformation values */
3435 if (*lpcbSecurityDescriptor < sizeof(*pSecurityDescriptor))
3436 return ERROR_INSUFFICIENT_BUFFER;
3438 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3439 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3441 return ERROR_SUCCESS;
3445 /******************************************************************************
3446 * RegLoadKey32W [ADVAPI32.???]
3448 * PARAMS
3449 * hkey [I] Handle of open key
3450 * lpszSubKey [I] Address of name of subkey
3451 * lpszFile [I] Address of filename for registry information
3453 LONG WINAPI RegLoadKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3455 LPKEYSTRUCT lpkey;
3456 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3458 /* Do this check before the hkey check */
3459 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3460 return ERROR_INVALID_PARAMETER;
3462 lpkey = lookup_hkey( hkey );
3463 if (!lpkey)
3464 return ERROR_INVALID_HANDLE;
3466 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3467 debugstr_w(lpszFile));
3469 return ERROR_SUCCESS;
3473 /******************************************************************************
3474 * RegLoadKey32A [ADVAPI32.???]
3476 LONG WINAPI RegLoadKey32A( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3478 LONG ret;
3479 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3480 LPWSTR lpszFileW = strdupA2W(lpszFile);
3481 ret = RegLoadKey32W( hkey, lpszSubKeyW, lpszFileW );
3482 if(lpszFileW) free(lpszFileW);
3483 if(lpszSubKeyW) free(lpszSubKeyW);
3484 return ret;
3488 /******************************************************************************
3489 * RegNotifyChangeKeyValue [ADVAPI32.???]
3491 * PARAMS
3492 * hkey [I] Handle of key to watch
3493 * fWatchSubTree [I] Flag for subkey notification
3494 * fdwNotifyFilter [I] Changes to be reported
3495 * hEvent [I] Handle of signaled event
3496 * fAsync [I] Flag for asynchronous reporting
3498 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL32 fWatchSubTree,
3499 DWORD fdwNotifyFilter, HANDLE32 hEvent,
3500 BOOL32 fAsync )
3502 LPKEYSTRUCT lpkey;
3503 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3504 hEvent,fAsync);
3506 lpkey = lookup_hkey( hkey );
3507 if (!lpkey)
3508 return ERROR_INVALID_HANDLE;
3510 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3511 hEvent,fAsync);
3513 return ERROR_SUCCESS;
3517 /******************************************************************************
3518 * RegUnLoadKey32W [ADVAPI32.173]
3520 * PARAMS
3521 * hkey [I] Handle of open key
3522 * lpSubKey [I] Address of name of subkey to unload
3524 LONG WINAPI RegUnLoadKey32W( HKEY hkey, LPCWSTR lpSubKey )
3526 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3527 return ERROR_SUCCESS;
3531 /******************************************************************************
3532 * RegUnLoadKey32A [ADVAPI32.172]
3534 LONG WINAPI RegUnLoadKey32A( HKEY hkey, LPCSTR lpSubKey )
3536 LONG ret;
3537 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3538 ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3539 if(lpSubKeyW) free(lpSubKeyW);
3540 return ret;
3544 /******************************************************************************
3545 * RegSetKeySecurity [ADVAPI32.167]
3547 * PARAMS
3548 * hkey [I] Open handle of key to set
3549 * SecurityInfo [I] Descriptor contents
3550 * pSecurityDesc [I] Address of descriptor for key
3552 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3553 PSECURITY_DESCRIPTOR pSecurityDesc )
3555 LPKEYSTRUCT lpkey;
3557 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3559 /* It seems to perform this check before the hkey check */
3560 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3561 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3562 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3563 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3564 /* Param OK */
3565 } else
3566 return ERROR_INVALID_PARAMETER;
3568 if (!pSecurityDesc)
3569 return ERROR_INVALID_PARAMETER;
3571 lpkey = lookup_hkey( hkey );
3572 if (!lpkey)
3573 return ERROR_INVALID_HANDLE;
3575 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3577 return ERROR_SUCCESS;
3581 /******************************************************************************
3582 * RegSaveKey32W [ADVAPI32.166]
3584 * PARAMS
3585 * hkey [I] Handle of key where save begins
3586 * lpFile [I] Address of filename to save to
3587 * sa [I] Address of security structure
3589 LONG WINAPI RegSaveKey32W( HKEY hkey, LPCWSTR lpFile,
3590 LPSECURITY_ATTRIBUTES sa )
3592 LPKEYSTRUCT lpkey;
3594 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3596 /* It appears to do this check before the hkey check */
3597 if (!lpFile || !*lpFile)
3598 return ERROR_INVALID_PARAMETER;
3600 lpkey = lookup_hkey( hkey );
3601 if (!lpkey)
3602 return ERROR_INVALID_HANDLE;
3604 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3606 return ERROR_SUCCESS;
3610 /******************************************************************************
3611 * RegSaveKey32A [ADVAPI32.165]
3613 LONG WINAPI RegSaveKey32A( HKEY hkey, LPCSTR lpFile,
3614 LPSECURITY_ATTRIBUTES sa )
3616 LONG ret;
3617 LPWSTR lpFileW = strdupA2W(lpFile);
3618 ret = RegSaveKey32W( hkey, lpFileW, sa );
3619 free(lpFileW);
3620 return ret;
3624 /******************************************************************************
3625 * RegRestoreKey32W [ADVAPI32.164]
3627 * PARAMS
3628 * hkey [I] Handle of key where restore begins
3629 * lpFile [I] Address of filename containing saved tree
3630 * dwFlags [I] Optional flags
3632 LONG WINAPI RegRestoreKey32W( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3634 LPKEYSTRUCT lpkey;
3636 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3638 /* It seems to do this check before the hkey check */
3639 if (!lpFile || !*lpFile)
3640 return ERROR_INVALID_PARAMETER;
3642 lpkey = lookup_hkey( hkey );
3643 if (!lpkey)
3644 return ERROR_INVALID_HANDLE;
3646 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3648 /* Check for file existence */
3650 return ERROR_SUCCESS;
3654 /******************************************************************************
3655 * RegRestoreKey32A [ADVAPI32.163]
3657 LONG WINAPI RegRestoreKey32A( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3659 LONG ret;
3660 LPWSTR lpFileW = strdupA2W(lpFile);
3661 ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3662 if(lpFileW) free(lpFileW);
3663 return ret;
3667 /******************************************************************************
3668 * RegReplaceKey32W [ADVAPI32.162]
3670 * PARAMS
3671 * hkey [I] Handle of open key
3672 * lpSubKey [I] Address of name of subkey
3673 * lpNewFile [I] Address of filename for file with new data
3674 * lpOldFile [I] Address of filename for backup file
3676 LONG WINAPI RegReplaceKey32W( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3677 LPCWSTR lpOldFile )
3679 LPKEYSTRUCT lpkey;
3681 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3682 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3684 lpkey = lookup_hkey( hkey );
3685 if (!lpkey)
3686 return ERROR_INVALID_HANDLE;
3688 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3689 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3691 return ERROR_SUCCESS;
3695 /******************************************************************************
3696 * RegReplaceKey32A [ADVAPI32.161]
3698 LONG WINAPI RegReplaceKey32A( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3699 LPCSTR lpOldFile )
3701 LONG ret;
3702 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3703 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3704 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3705 ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3706 free(lpOldFileW);
3707 free(lpNewFileW);
3708 free(lpSubKeyW);
3709 return ret;