Workaroung gcc 2.7.2.x sig 11 issue.
[wine.git] / misc / registry.c
blob4b2c99c8bbc6622c2703a8b94a942376eb66da9b
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
12 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <sys/errno.h>
28 #include <sys/types.h>
29 #include <sys/fcntl.h>
30 #include <sys/stat.h>
31 #include <assert.h>
32 #include <time.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wine/winbase16.h"
36 #include "wine/winestring.h"
37 #include "winerror.h"
38 #include "file.h"
39 #include "heap.h"
40 #include "debugtools.h"
41 #include "xmalloc.h"
42 #include "options.h"
43 #include "winreg.h"
44 #include "winversion.h"
46 DECLARE_DEBUG_CHANNEL(reg)
47 DECLARE_DEBUG_CHANNEL(string)
49 static void REGISTRY_Init(void);
50 /* FIXME: following defines should be configured global ... */
52 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
53 #define WINE_PREFIX "/.wine"
54 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
55 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
57 /* relative in ~user/.wine/ : */
58 #define SAVE_CURRENT_USER "user.reg"
59 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
60 #define SAVE_LOCAL_MACHINE "system.reg"
62 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
63 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
65 /* one value of a key */
66 typedef struct tagKEYVALUE
68 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
69 DWORD type; /* type of value */
70 DWORD len; /* length of data in BYTEs */
71 DWORD lastmodified; /* time of seconds since 1.1.1970 */
72 LPBYTE data; /* content, may be strings, binaries, etc. */
73 } KEYVALUE,*LPKEYVALUE;
75 /* a registry key */
76 typedef struct tagKEYSTRUCT
78 LPWSTR keyname; /* name of THIS key (UNICODE) */
79 DWORD flags; /* flags. */
80 LPWSTR class;
81 /* values */
82 DWORD nrofvalues; /* nr of values in THIS key */
83 LPKEYVALUE values; /* values in THIS key */
84 /* key management pointers */
85 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
86 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
87 } KEYSTRUCT, *LPKEYSTRUCT;
90 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
91 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
92 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
93 static KEYSTRUCT *key_users=NULL; /* all users? */
95 /* dynamic, not saved */
96 static KEYSTRUCT *key_performance_data=NULL;
97 static KEYSTRUCT *key_current_config=NULL;
98 static KEYSTRUCT *key_dyn_data=NULL;
100 /* what valuetypes do we need to convert? */
101 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
104 static struct openhandle {
105 LPKEYSTRUCT lpkey;
106 HKEY hkey;
107 REGSAM accessmask;
108 } *openhandles=NULL;
109 static int nrofopenhandles=0;
110 /* Starts after 1 because 0,1 are reserved for Win16 */
111 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
112 HKEYs for remote registry access */
113 static int currenthandle=2;
117 * QUESTION
118 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
119 * If so, can we remove them?
120 * ANSWER
121 * No, the memory handling functions are called very often in here,
122 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
123 * loading 100 times slower. -MM
125 static LPWSTR strdupA2W(LPCSTR src)
127 if(src) {
128 LPWSTR dest=xmalloc(2*strlen(src)+2);
129 lstrcpyAtoW(dest,src);
130 return dest;
132 return NULL;
135 static LPWSTR strdupW(LPCWSTR a) {
136 LPWSTR b;
137 int len;
139 if(a) {
140 len=sizeof(WCHAR)*(lstrlenW(a)+1);
141 b=(LPWSTR)xmalloc(len);
142 memcpy(b,a,len);
143 return b;
145 return NULL;
148 LPWSTR strcvtA2W(LPCSTR src, int nchars)
151 LPWSTR dest = xmalloc (2 * nchars + 2);
153 lstrcpynAtoW(dest,src,nchars+1);
154 dest[nchars] = 0;
155 return dest;
158 * we need to convert A to W with '\0' in strings (MULTI_SZ)
161 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
162 { LPWSTR p = dst;
164 TRACE_(reg)("\"%s\" %i\n",src, n);
166 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
168 return dst;
170 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
171 { LPSTR p = dst;
173 TRACE_(string)("L\"%s\" %i\n",debugstr_w(src), n);
175 while (n-- > 0) *p++ = (CHAR)*src++;
177 return dst;
180 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
182 if (TRACE_ON(reg) && lpbData)
184 switch(key->type)
186 case REG_EXPAND_SZ:
187 case REG_SZ:
188 TRACE_(reg)(" Value %s, Data(sz)=%s\n",
189 debugstr_w(key->name),
190 debugstr_w((LPCWSTR)lpbData));
191 break;
193 case REG_DWORD:
194 TRACE_(reg)(" Value %s, Data(dword)=0x%08lx\n",
195 debugstr_w(key->name),
196 (DWORD)*lpbData);
197 break;
199 case REG_MULTI_SZ:
201 int i;
202 LPCWSTR ptr = (LPCWSTR)lpbData;
203 for (i=0;ptr[0];i++)
205 TRACE_(reg)(" Value %s, MULTI_SZ(%i=%s)\n",
206 debugstr_w(key->name),
208 debugstr_w(ptr));
210 ptr += lstrlenW(ptr)+1;
213 break;
215 default:
217 char szTemp[100]; /* 3*32 + 3 + 1 */
218 int i;
219 for ( i = 0; i < key->len ; i++)
221 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
222 if (i>=31)
224 sprintf (&(szTemp[i*3+3]),"...");
225 break;
228 TRACE_(reg)(" Value %s, Data(raw)=(%s)\n",
229 debugstr_w(key->name),
230 szTemp);
232 } /* switch */
233 } /* if */
237 /******************************************************************************
238 * is_standard_hkey [Internal]
239 * Determines if a hkey is a standard key
241 static BOOL is_standard_hkey( HKEY hkey )
243 switch(hkey) {
244 case 0x00000000:
245 case 0x00000001:
246 case HKEY_CLASSES_ROOT:
247 case HKEY_CURRENT_CONFIG:
248 case HKEY_CURRENT_USER:
249 case HKEY_LOCAL_MACHINE:
250 case HKEY_USERS:
251 case HKEY_PERFORMANCE_DATA:
252 case HKEY_DYN_DATA:
253 return TRUE;
254 default:
255 return FALSE;
259 /******************************************************************************
260 * add_handle [Internal]
262 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
264 int i;
266 TRACE_(reg)("(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
267 /* Check for duplicates */
268 for (i=0;i<nrofopenhandles;i++) {
269 if (openhandles[i].lpkey==lpkey) {
270 /* This is not really an error - the user is allowed to create
271 two (or more) handles to the same key */
272 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
274 if (openhandles[i].hkey==hkey) {
275 WARN_(reg)("Adding handle %x twice\n",hkey);
278 openhandles=xrealloc( openhandles,
279 sizeof(struct openhandle)*(nrofopenhandles+1));
281 openhandles[i].lpkey = lpkey;
282 openhandles[i].hkey = hkey;
283 openhandles[i].accessmask = accessmask;
284 nrofopenhandles++;
288 /******************************************************************************
289 * get_handle [Internal]
291 * RETURNS
292 * Success: Pointer to key
293 * Failure: NULL
295 static LPKEYSTRUCT get_handle( HKEY hkey )
297 int i;
299 for (i=0; i<nrofopenhandles; i++)
300 if (openhandles[i].hkey == hkey)
301 return openhandles[i].lpkey;
302 WARN_(reg)("Could not find handle 0x%x\n",hkey);
303 return NULL;
307 /******************************************************************************
308 * remove_handle [Internal]
310 * PARAMS
311 * hkey [I] Handle of key to remove
313 * RETURNS
314 * Success: ERROR_SUCCESS
315 * Failure: ERROR_INVALID_HANDLE
317 static DWORD remove_handle( HKEY hkey )
319 int i;
321 for (i=0;i<nrofopenhandles;i++)
322 if (openhandles[i].hkey==hkey)
323 break;
325 if (i == nrofopenhandles) {
326 WARN_(reg)("Could not find handle 0x%x\n",hkey);
327 return ERROR_INVALID_HANDLE;
330 memcpy( openhandles+i,
331 openhandles+i+1,
332 sizeof(struct openhandle)*(nrofopenhandles-i-1)
334 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
335 nrofopenhandles--;
336 return ERROR_SUCCESS;
339 /******************************************************************************
340 * lookup_hkey [Internal]
342 * Just as the name says. Creates the root keys on demand, so we can call the
343 * Reg* functions at any time.
345 * RETURNS
346 * Success: Pointer to key structure
347 * Failure: NULL
349 #define ADD_ROOT_KEY(xx) \
350 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
351 memset(xx,'\0',sizeof(KEYSTRUCT));\
352 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
354 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
356 switch (hkey) {
357 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
358 * some programs. Do not remove those cases. -MM
360 case 0x00000000:
361 case 0x00000001:
362 case HKEY_CLASSES_ROOT:
364 if (!key_classes_root)
366 HKEY cl_r_hkey;
368 /* calls lookup_hkey recursively, TWICE */
369 if ( RegCreateKey16(
370 HKEY_LOCAL_MACHINE,
371 "SOFTWARE\\Classes",
372 &cl_r_hkey) != ERROR_SUCCESS)
374 ERR_(reg)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
375 exit(1);
378 key_classes_root = lookup_hkey(cl_r_hkey);
380 return key_classes_root;
383 case HKEY_CURRENT_USER:
384 if (!key_current_user) {
385 ADD_ROOT_KEY(key_current_user);
387 return key_current_user;
389 case HKEY_LOCAL_MACHINE:
390 if (!key_local_machine) {
391 ADD_ROOT_KEY(key_local_machine);
392 REGISTRY_Init();
394 return key_local_machine;
396 case HKEY_USERS:
397 if (!key_users) {
398 ADD_ROOT_KEY(key_users);
400 return key_users;
402 case HKEY_PERFORMANCE_DATA:
403 if (!key_performance_data) {
404 ADD_ROOT_KEY(key_performance_data);
406 return key_performance_data;
408 case HKEY_DYN_DATA:
409 if (!key_dyn_data) {
410 ADD_ROOT_KEY(key_dyn_data);
412 return key_dyn_data;
414 case HKEY_CURRENT_CONFIG:
415 if (!key_current_config) {
416 ADD_ROOT_KEY(key_current_config);
418 return key_current_config;
420 default:
421 return get_handle(hkey);
424 /*NOTREACHED*/
426 #undef ADD_ROOT_KEY
427 /* so we don't accidently access them ... */
428 #define key_current_config NULL NULL
429 #define key_current_user NULL NULL
430 #define key_users NULL NULL
431 #define key_local_machine NULL NULL
432 #define key_classes_root NULL NULL
433 #define key_dyn_data NULL NULL
434 #define key_performance_data NULL NULL
436 /******************************************************************************
437 * split_keypath [Internal]
438 * splits the unicode string 'wp' into an array of strings.
439 * the array is allocated by this function.
440 * Free the array using FREE_KEY_PATH
442 * PARAMS
443 * wp [I] String to split up
444 * wpv [O] Array of pointers to strings
445 * wpc [O] Number of components
447 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
449 int i,j,len;
450 LPWSTR ws;
452 TRACE_(reg)("(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
454 ws = HEAP_strdupW( SystemHeap, 0, wp );
456 /* We know we have at least one substring */
457 *wpc = 1;
459 /* Replace each backslash with NULL, and increment the count */
460 for (i=0;ws[i];i++) {
461 if (ws[i]=='\\') {
462 ws[i]=0;
463 (*wpc)++;
467 len = i;
469 /* Allocate the space for the array of pointers, leaving room for the
470 NULL at the end */
471 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
472 (*wpv)[0]= ws;
474 /* Assign each pointer to the appropriate character in the string */
475 j = 1;
476 for (i=1;i<len;i++)
477 if (ws[i-1]==0) {
478 (*wpv)[j++]=ws+i;
479 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
482 (*wpv)[j]=NULL;
484 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
489 /******************************************************************************
490 * REGISTRY_Init [Internal]
491 * Registry initialisation, allocates some default keys.
493 static void REGISTRY_Init(void) {
494 HKEY hkey;
495 char buf[200];
497 TRACE_(reg)("(void)\n");
499 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
500 RegCloseKey(hkey);
502 /* This was an Open, but since it is called before the real registries
503 are loaded, it was changed to a Create - MTB 980507*/
504 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
505 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
506 RegCloseKey(hkey);
508 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
509 * CurrentVersion
510 * CurrentBuildNumber
511 * CurrentType
512 * string RegisteredOwner
513 * string RegisteredOrganization
516 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
517 * string SysContact
518 * string SysLocation
519 * SysServices
521 if (-1!=gethostname(buf,200)) {
522 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
523 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
524 RegCloseKey(hkey);
529 /************************ SAVE Registry Function ****************************/
531 #define REGISTRY_SAVE_VERSION 0x00000001
533 /* Registry saveformat:
534 * If you change it, increase above number by 1, which will flush
535 * old registry database files.
537 * Global:
538 * "WINE REGISTRY Version %d"
539 * subkeys....
540 * Subkeys:
541 * keyname
542 * valuename=lastmodified,type,data
543 * ...
544 * subkeys
545 * ...
546 * keyname,valuename,stringdata:
547 * the usual ascii characters from 0x00-0xff (well, not 0x00)
548 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
549 * ( "=\\\t" escaped in \uXXXX form.)
550 * type,lastmodified:
551 * int
553 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
555 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
556 * SaveOnlyUpdatedKeys=yes
559 /******************************************************************************
560 * _save_check_tainted [Internal]
562 static int _save_check_tainted( LPKEYSTRUCT lpkey )
564 int tainted;
566 if (!lpkey)
567 return 0;
568 if (lpkey->flags & REG_OPTION_TAINTED)
569 tainted = 1;
570 else
571 tainted = 0;
572 while (lpkey) {
573 if (_save_check_tainted(lpkey->nextsub)) {
574 lpkey->flags |= REG_OPTION_TAINTED;
575 tainted = 1;
577 lpkey = lpkey->next;
579 return tainted;
582 /******************************************************************************
583 * _save_USTRING [Internal]
585 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
587 LPWSTR s;
588 int doescape;
590 if (wstr==NULL)
591 return;
592 s=wstr;
593 while (*s) {
594 doescape=0;
595 if (*s>0xff)
596 doescape = 1;
597 if (*s=='\n')
598 doescape = 1;
599 if (escapeeq && *s=='=')
600 doescape = 1;
601 if (*s=='\\')
602 fputc(*s,F); /* if \\ then put it twice. */
603 if (doescape)
604 fprintf(F,"\\u%04x",*((unsigned short*)s));
605 else
606 fputc(*s,F);
607 s++;
611 /******************************************************************************
612 * _savesubkey [Internal]
614 * NOTES
615 * REG_MULTI_SZ is handled as binary (like in win95) (js)
617 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
619 LPKEYSTRUCT lpxkey;
620 int i,tabs,j;
622 lpxkey = lpkey;
623 while (lpxkey) {
624 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
625 (all || (lpxkey->flags & REG_OPTION_TAINTED))
627 for (tabs=level;tabs--;)
628 fputc('\t',F);
629 _save_USTRING(F,lpxkey->keyname,1);
630 fputs("\n",F);
631 for (i=0;i<lpxkey->nrofvalues;i++) {
632 LPKEYVALUE val=lpxkey->values+i;
634 for (tabs=level+1;tabs--;)
635 fputc('\t',F);
636 _save_USTRING(F,val->name,0);
637 fputc('=',F);
638 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
639 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
640 _save_USTRING(F,(LPWSTR)val->data,0);
641 else
642 for (j=0;j<val->len;j++)
643 fprintf(F,"%02x",*((unsigned char*)val->data+j));
644 fputs("\n",F);
646 /* descend recursively */
647 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
648 return 0;
650 lpxkey=lpxkey->next;
652 return 1;
656 /******************************************************************************
657 * _savesubreg [Internal]
659 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
661 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
662 _save_check_tainted(lpkey->nextsub);
663 return _savesubkey(F,lpkey->nextsub,0,all);
667 /******************************************************************************
668 * _savereg [Internal]
670 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
672 FILE *F;
674 F=fopen(fn,"w");
675 if (F==NULL) {
676 WARN_(reg)("Couldn't open %s for writing: %s\n",
677 fn,strerror(errno)
679 return FALSE;
681 if (!_savesubreg(F,lpkey,all)) {
682 fclose(F);
683 unlink(fn);
684 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
685 return FALSE;
687 fclose(F);
688 return TRUE;
692 /******************************************************************************
693 * SHELL_SaveRegistry [Internal]
695 void SHELL_SaveRegistry( void )
697 char *fn, *home, *tmp;
698 char buf[4];
699 HKEY hkey;
700 int all;
701 int usedCfgUser = 0;
702 int usedCfgLM = 0;
704 TRACE_(reg)("(void)\n");
706 all=0;
707 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
709 strcpy(buf,"yes");
711 else
713 DWORD len,junk,type;
715 len=4;
716 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
717 VAL_SAVEUPDATED,
718 &junk,
719 &type,
720 buf,
721 &len)) || (type!=REG_SZ))
723 strcpy(buf,"yes");
725 RegCloseKey(hkey);
728 if (lstrcmpiA(buf,"yes")) all=1;
730 if (!(home = getenv( "HOME" )))
732 WARN_(reg)("Failed to get homedirectory of UID %d.\n",getuid());
733 return;
736 * Save HKEY_CURRENT_USER
737 * Try first saving according to the defined location in .winerc
739 fn = xmalloc( MAX_PATHNAME_LEN );
740 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "", fn, MAX_PATHNAME_LEN - 1))
742 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
743 usedCfgUser = 1;
745 free (fn);
747 if (usedCfgUser != 1)
749 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
750 strlen(SAVE_CURRENT_USER) + 2 );
751 strcpy(fn,home);
752 strcat(fn,WINE_PREFIX);
754 /* create the directory. don't care about errorcodes. */
755 mkdir(fn,0755); /* drwxr-xr-x */
756 strcat(fn,"/"SAVE_CURRENT_USER);
758 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
759 strcpy(tmp,fn);
760 strcat(tmp,".tmp");
762 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
763 if (-1==rename(tmp,fn)) {
764 perror("rename tmp registry");
765 unlink(tmp);
768 free(tmp);
769 free(fn);
773 * Save HKEY_LOCAL_MACHINE
774 * Try first saving according to the defined location in .winerc
776 fn = xmalloc ( MAX_PATHNAME_LEN);
777 if (PROFILE_GetWineIniString ( "Registry", "LocalMachineFileName", "", fn,
778 MAX_PATHNAME_LEN - 1))
780 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
781 usedCfgLM = 1;
783 free (fn);
785 if ( usedCfgLM != 1)
787 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
788 strcpy(fn,home);
789 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
791 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
792 strcpy(tmp,fn);
793 strcat(tmp,".tmp");
795 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
796 if (-1==rename(tmp,fn)) {
797 perror("rename tmp registry");
798 unlink(tmp);
801 free(tmp);
802 free(fn);
806 * Save HKEY_USERS
808 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
810 strcpy(fn,home);
811 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
813 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
814 strcpy(tmp,fn);strcat(tmp,".tmp");
815 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
816 if (-1==rename(tmp,fn)) {
817 perror("rename tmp registry");
818 unlink(tmp);
821 free(tmp);
822 free(fn);
826 /************************ LOAD Registry Function ****************************/
830 /******************************************************************************
831 * _find_or_add_key [Internal]
833 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
835 LPKEYSTRUCT lpxkey,*lplpkey;
837 if ((!keyname) || (keyname[0]==0)) {
838 free(keyname);
839 return lpkey;
841 lplpkey= &(lpkey->nextsub);
842 lpxkey = *lplpkey;
843 while (lpxkey) {
844 if ( (lpxkey->keyname[0]==keyname[0]) &&
845 !lstrcmpiW(lpxkey->keyname,keyname)
847 break;
848 lplpkey = &(lpxkey->next);
849 lpxkey = *lplpkey;
851 if (lpxkey==NULL) {
852 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
853 lpxkey = *lplpkey;
854 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
855 lpxkey->keyname = keyname;
856 } else
857 free(keyname);
858 return lpxkey;
861 /******************************************************************************
862 * _find_or_add_value [Internal]
864 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
865 LPBYTE data, DWORD len, DWORD lastmodified )
867 LPKEYVALUE val=NULL;
868 int i;
870 if (name && !*name) {/* empty string equals default (NULL) value */
871 free(name);
872 name = NULL;
875 for (i=0;i<lpkey->nrofvalues;i++) {
876 val=lpkey->values+i;
877 if (name==NULL) {
878 if (val->name==NULL)
879 break;
880 } else {
881 if ( val->name!=NULL &&
882 val->name[0]==name[0] &&
883 !lstrcmpiW(val->name,name)
885 break;
888 if (i==lpkey->nrofvalues) {
889 lpkey->values = xrealloc(
890 lpkey->values,
891 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
893 val=lpkey->values+i;
894 memset(val,'\0',sizeof(KEYVALUE));
895 val->name = name;
896 } else {
897 if (name)
898 free(name);
900 if (val->lastmodified<lastmodified) {
901 val->lastmodified=lastmodified;
902 val->type = type;
904 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
906 data=xmalloc(sizeof(WCHAR));
907 memset(data,0,sizeof(WCHAR));
908 len =sizeof(WCHAR);
911 val->len = len;
912 if (val->data)
913 free(val->data);
914 val->data = data;
915 } else
916 free(data);
920 /******************************************************************************
921 * _wine_read_line [Internal]
923 * reads a line including dynamically enlarging the readbuffer and throwing
924 * away comments
926 static int _wine_read_line( FILE *F, char **buf, int *len )
928 char *s,*curread;
929 int mylen,curoff;
931 curread = *buf;
932 mylen = *len;
933 **buf = '\0';
934 while (1) {
935 while (1) {
936 s=fgets(curread,mylen,F);
937 if (s==NULL)
938 return 0; /* EOF */
939 if (NULL==(s=strchr(curread,'\n'))) {
940 /* buffer wasn't large enough */
941 curoff = strlen(*buf);
942 *buf = xrealloc(*buf,*len*2);
943 curread = *buf + curoff;
944 mylen = *len; /* we filled up the buffer and
945 * got new '*len' bytes to fill
947 *len = *len * 2;
948 } else {
949 *s='\0';
950 break;
953 /* throw away comments */
954 if (**buf=='#' || **buf==';') {
955 curread = *buf;
956 mylen = *len;
957 continue;
959 if (s) /* got end of line */
960 break;
962 return 1;
966 /******************************************************************************
967 * _wine_read_USTRING [Internal]
969 * converts a char* into a UNICODE string (up to a special char)
970 * and returns the position exactly after that string
972 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
974 char *s;
975 LPWSTR ws;
977 /* read up to "=" or "\0" or "\n" */
978 s = buf;
979 if (*s == '=') {
980 /* empty string is the win3.1 default value(NULL)*/
981 *str = NULL;
982 return s;
984 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
985 ws = *str;
986 while (*s && (*s!='\n') && (*s!='=')) {
987 if (*s!='\\')
988 *ws++=*((unsigned char*)s++);
989 else {
990 s++;
991 if (!*s) {
992 /* Dangling \ ... may only happen if a registry
993 * write was short. FIXME: What do to?
995 break;
997 if (*s=='\\') {
998 *ws++='\\';
999 s++;
1000 continue;
1002 if (*s!='u') {
1003 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1004 *ws++='\\';
1005 *ws++=*s++;
1006 } else {
1007 char xbuf[5];
1008 int wc;
1010 s++;
1011 memcpy(xbuf,s,4);xbuf[4]='\0';
1012 if (!sscanf(xbuf,"%x",&wc))
1013 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1014 s+=4;
1015 *ws++ =(unsigned short)wc;
1019 *ws = 0;
1020 ws = *str;
1021 if (*ws)
1022 *str = strdupW(*str);
1023 else
1024 *str = NULL;
1025 free(ws);
1026 return s;
1030 /******************************************************************************
1031 * _wine_loadsubkey [Internal]
1033 * NOTES
1034 * It seems like this is returning a boolean. Should it?
1036 * RETURNS
1037 * Success: 1
1038 * Failure: 0
1040 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1041 int *buflen, DWORD optflag )
1043 LPKEYSTRUCT lpxkey;
1044 int i;
1045 char *s;
1046 LPWSTR name;
1048 TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1049 *buflen, optflag);
1051 lpkey->flags |= optflag;
1053 /* Good. We already got a line here ... so parse it */
1054 lpxkey = NULL;
1055 while (1) {
1056 i=0;s=*buf;
1057 while (*s=='\t') {
1058 s++;
1059 i++;
1061 if (i>level) {
1062 if (lpxkey==NULL) {
1063 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1064 return 0;
1066 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1067 continue;
1070 /* let the caller handle this line */
1071 if (i<level || **buf=='\0')
1072 return 1;
1074 /* it can be: a value or a keyname. Parse the name first */
1075 s=_wine_read_USTRING(s,&name);
1077 /* switch() default: hack to avoid gotos */
1078 switch (0) {
1079 default:
1080 if (*s=='\0') {
1081 lpxkey=_find_or_add_key(lpkey,name);
1082 } else {
1083 LPBYTE data;
1084 int len,lastmodified,type;
1086 if (*s!='=') {
1087 WARN_(reg)("Unexpected character: %c\n",*s);
1088 break;
1090 s++;
1091 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1092 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1093 break;
1095 /* skip the 2 , */
1096 s=strchr(s,',');s++;
1097 s=strchr(s,',');s++;
1098 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1099 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1100 if (data)
1101 len = lstrlenW((LPWSTR)data)*2+2;
1102 else
1103 len = 0;
1104 } else {
1105 len=strlen(s)/2;
1106 data = (LPBYTE)xmalloc(len+1);
1107 for (i=0;i<len;i++) {
1108 data[i]=0;
1109 if (*s>='0' && *s<='9')
1110 data[i]=(*s-'0')<<4;
1111 if (*s>='a' && *s<='f')
1112 data[i]=(*s-'a'+'\xa')<<4;
1113 if (*s>='A' && *s<='F')
1114 data[i]=(*s-'A'+'\xa')<<4;
1115 s++;
1116 if (*s>='0' && *s<='9')
1117 data[i]|=*s-'0';
1118 if (*s>='a' && *s<='f')
1119 data[i]|=*s-'a'+'\xa';
1120 if (*s>='A' && *s<='F')
1121 data[i]|=*s-'A'+'\xa';
1122 s++;
1125 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1128 /* read the next line */
1129 if (!_wine_read_line(F,buf,buflen))
1130 return 1;
1132 return 1;
1136 /******************************************************************************
1137 * _wine_loadsubreg [Internal]
1139 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1141 int ver;
1142 char *buf;
1143 int buflen;
1145 buf=xmalloc(10);buflen=10;
1146 if (!_wine_read_line(F,&buf,&buflen)) {
1147 free(buf);
1148 return 0;
1150 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1151 free(buf);
1152 return 0;
1154 if (ver!=REGISTRY_SAVE_VERSION) {
1155 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1156 free(buf);
1157 return 0;
1159 if (!_wine_read_line(F,&buf,&buflen)) {
1160 free(buf);
1161 return 0;
1163 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1164 free(buf);
1165 return 0;
1167 free(buf);
1168 return 1;
1172 /******************************************************************************
1173 * _wine_loadreg [Internal]
1175 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1177 FILE *F;
1179 TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1181 F = fopen(fn,"rb");
1182 if (F==NULL) {
1183 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1184 return;
1186 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1187 fclose(F);
1188 unlink(fn);
1189 return;
1191 fclose(F);
1194 /******************************************************************************
1195 * _flush_registry [Internal]
1197 * This function allow to flush section of the internal registry. It is mainly
1198 * implements to fix a problem with the global HKU and the local HKU.
1199 * Those two files are read to build the HKU\.Default branch to finaly copy
1200 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1201 * all the global HKU are saved onto the user's personal version of HKU hive.
1202 * which is bad...
1205 /* Forward declaration of recusive agent */
1206 static void _flush_reg(LPKEYSTRUCT from);
1208 static void _flush_registry( LPKEYSTRUCT from )
1210 /* make sure we have something... */
1211 if (from == NULL)
1212 return;
1214 /* Launch the recusive agent on sub branches */
1215 _flush_reg( from->nextsub );
1216 _flush_reg( from->next );
1218 /* Initialize pointers */
1219 from->nextsub = NULL;
1220 from->next = NULL;
1222 static void _flush_reg( LPKEYSTRUCT from )
1224 int j;
1226 /* make sure we have something... */
1227 if (from == NULL)
1228 return;
1231 * do the same for the child keys
1233 if (from->nextsub != NULL)
1234 _flush_reg(from->nextsub);
1237 * do the same for the sibling keys
1239 if (from->next != NULL)
1240 _flush_reg(from->next);
1243 * iterate through this key's values and delete them
1245 for (j=0;j<from->nrofvalues;j++)
1247 free( (from->values+j)->name);
1248 free( (from->values+j)->data);
1252 * free the structure
1254 if ( from != NULL )
1255 free(from);
1259 /******************************************************************************
1260 * _copy_registry [Internal]
1262 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1264 LPKEYSTRUCT lpxkey;
1265 int j;
1266 LPKEYVALUE valfrom;
1268 from=from->nextsub;
1269 while (from) {
1270 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1272 for (j=0;j<from->nrofvalues;j++) {
1273 LPWSTR name;
1274 LPBYTE data;
1276 valfrom = from->values+j;
1277 name=valfrom->name;
1278 if (name) name=strdupW(name);
1279 data=(LPBYTE)xmalloc(valfrom->len);
1280 memcpy(data,valfrom->data,valfrom->len);
1282 _find_or_add_value(
1283 lpxkey,
1284 name,
1285 valfrom->type,
1286 data,
1287 valfrom->len,
1288 valfrom->lastmodified
1291 _copy_registry(from,lpxkey);
1292 from = from->next;
1297 /* WINDOWS 95 REGISTRY LOADER */
1299 * Structure of a win95 registry database.
1300 * main header:
1301 * 0 : "CREG" - magic
1302 * 4 : DWORD version
1303 * 8 : DWORD offset_of_RGDB_part
1304 * 0C..0F: ? (someone fill in please)
1305 * 10: WORD number of RGDB blocks
1306 * 12: WORD ?
1307 * 14: WORD always 0000?
1308 * 16: WORD always 0001?
1309 * 18..1F: ? (someone fill in please)
1311 * 20: RGKN_section:
1312 * header:
1313 * 0 : "RGKN" - magic
1314 * 4 : DWORD offset to first RGDB section
1315 * 8 : DWORD offset to the root record
1316 * C..0x1B: ? (fill in)
1317 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1319 * Disk Key Entry Structure:
1320 * 00: DWORD - Free entry indicator(?)
1321 * 04: DWORD - Hash = sum of bytes of keyname
1322 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1323 * 0C: DWORD - disk address of PreviousLevel Key.
1324 * 10: DWORD - disk address of Next Sublevel Key.
1325 * 14: DWORD - disk address of Next Key (on same level).
1326 * DKEP>18: WORD - Nr, Low Significant part.
1327 * 1A: WORD - Nr, High Significant part.
1329 * The disk address always points to the nr part of the previous key entry
1330 * of the referenced key. Don't ask me why, or even if I got this correct
1331 * from staring at 1kg of hexdumps. (DKEP)
1333 * The High significant part of the structure seems to equal the number
1334 * of the RGDB section. The low significant part is a unique ID within
1335 * that RGDB section
1337 * There are two minor corrections to the position of that structure.
1338 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1339 * the DKE reread from there.
1340 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1341 * CPS - I have not experienced the above phenomenon in my registry files
1343 * RGDB_section:
1344 * 00: "RGDB" - magic
1345 * 04: DWORD offset to next RGDB section
1346 * 08: DWORD ?
1347 * 0C: WORD always 000d?
1348 * 0E: WORD RGDB block number
1349 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1350 * 14..1F: ?
1351 * 20.....: disk keys
1353 * disk key:
1354 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1355 * 08: WORD nrLS - low significant part of NR
1356 * 0A: WORD nrHS - high significant part of NR
1357 * 0C: DWORD bytesused - bytes used in this structure.
1358 * 10: WORD name_len - length of name in bytes. without \0
1359 * 12: WORD nr_of_values - number of values.
1360 * 14: char name[name_len] - name string. No \0.
1361 * 14+name_len: disk values
1362 * nextkeyoffset: ... next disk key
1364 * disk value:
1365 * 00: DWORD type - value type (hmm, could be WORD too)
1366 * 04: DWORD - unknown, usually 0
1367 * 08: WORD namelen - length of Name. 0 means name=NULL
1368 * 0C: WORD datalen - length of Data.
1369 * 10: char name[namelen] - name, no \0
1370 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1371 * 10+namelen+datalen: next values or disk key
1373 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1374 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1375 * structure) and reading another RGDB_section.
1376 * repeat until end of file.
1378 * An interesting relationship exists in RGDB_section. The value at offset
1379 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1380 * idea at the moment what this means. (Kevin Cozens)
1382 * FIXME: this description needs some serious help, yes.
1385 struct _w95keyvalue {
1386 unsigned long type;
1387 unsigned short datalen;
1388 char *name;
1389 unsigned char *data;
1390 unsigned long x1;
1391 int lastmodified;
1394 struct _w95key {
1395 char *name;
1396 int nrofvals;
1397 struct _w95keyvalue *values;
1398 struct _w95key *prevlvl;
1399 struct _w95key *nextsub;
1400 struct _w95key *next;
1404 struct _w95_info {
1405 char *rgknbuffer;
1406 int rgknsize;
1407 char *rgdbbuffer;
1408 int rgdbsize;
1409 int depth;
1410 int lastmodified;
1414 /******************************************************************************
1415 * _w95_processKey [Internal]
1417 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1418 int nrLS, int nrMS, struct _w95_info *info )
1421 /* Disk Key Header structure (RGDB part) */
1422 struct dkh {
1423 unsigned long nextkeyoff;
1424 unsigned short nrLS;
1425 unsigned short nrMS;
1426 unsigned long bytesused;
1427 unsigned short keynamelen;
1428 unsigned short values;
1429 unsigned long xx1;
1430 /* keyname */
1431 /* disk key values or nothing */
1433 /* Disk Key Value structure */
1434 struct dkv {
1435 unsigned long type;
1436 unsigned long x1;
1437 unsigned short valnamelen;
1438 unsigned short valdatalen;
1439 /* valname, valdata */
1443 struct dkh dkh;
1444 int bytesread = 0;
1445 char *rgdbdata = info->rgdbbuffer;
1446 int nbytes = info->rgdbsize;
1447 char *curdata = rgdbdata;
1448 char *end = rgdbdata + nbytes;
1449 int off_next_rgdb;
1450 char *next = rgdbdata;
1451 int nrgdb, i;
1452 LPKEYSTRUCT lpxkey;
1454 do {
1455 curdata = next;
1456 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1458 memcpy(&off_next_rgdb,curdata+4,4);
1459 next = curdata + off_next_rgdb;
1460 nrgdb = (int) *((short *)curdata + 7);
1462 } while (nrgdb != nrMS && (next < end));
1464 /* curdata now points to the start of the right RGDB section */
1465 curdata += 0x20;
1467 #define XREAD(whereto,len) \
1468 if ((curdata + len) <= end) {\
1469 memcpy(whereto,curdata,len);\
1470 curdata+=len;\
1471 bytesread+=len;\
1474 while (curdata < next) {
1475 struct dkh *xdkh = (struct dkh*)curdata;
1477 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1478 if (xdkh->nrLS == nrLS) {
1479 memcpy(&dkh,xdkh,sizeof(dkh));
1480 curdata += sizeof(dkh);
1481 break;
1483 curdata += xdkh->nextkeyoff;
1486 if (dkh.nrLS != nrLS) return (NULL);
1488 if (nrgdb != dkh.nrMS)
1489 return (NULL);
1491 assert((dkh.keynamelen<2) || curdata[0]);
1492 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1493 curdata += dkh.keynamelen;
1495 for (i=0;i< dkh.values; i++) {
1496 struct dkv dkv;
1497 LPBYTE data;
1498 int len;
1499 LPWSTR name;
1501 XREAD(&dkv,sizeof(dkv));
1503 name = strcvtA2W(curdata, dkv.valnamelen);
1504 curdata += dkv.valnamelen;
1506 if ((1 << dkv.type) & UNICONVMASK) {
1507 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1508 len = 2*(dkv.valdatalen + 1);
1509 } else {
1510 /* I don't think we want to NULL terminate all data */
1511 data = xmalloc(dkv.valdatalen);
1512 memcpy (data, curdata, dkv.valdatalen);
1513 len = dkv.valdatalen;
1516 curdata += dkv.valdatalen;
1518 _find_or_add_value(
1519 lpxkey,
1520 name,
1521 dkv.type,
1522 data,
1523 len,
1524 info->lastmodified
1527 return (lpxkey);
1530 /******************************************************************************
1531 * _w95_walkrgkn [Internal]
1533 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1534 struct _w95_info *info )
1537 /* Disk Key Entry structure (RGKN part) */
1538 struct dke {
1539 unsigned long x1;
1540 unsigned long x2;
1541 unsigned long x3;/*usually 0xFFFFFFFF */
1542 unsigned long prevlvl;
1543 unsigned long nextsub;
1544 unsigned long next;
1545 unsigned short nrLS;
1546 unsigned short nrMS;
1547 } *dke = (struct dke *)off;
1548 LPKEYSTRUCT lpxkey;
1550 if (dke == NULL) {
1551 dke = (struct dke *) ((char *)info->rgknbuffer);
1554 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1555 /* XXX <-- This is a hack*/
1556 if (!lpxkey) {
1557 lpxkey = prevkey;
1560 if (dke->nextsub != -1 &&
1561 ((dke->nextsub - 0x20) < info->rgknsize)
1562 && (dke->nextsub > 0x20)) {
1564 _w95_walkrgkn(lpxkey,
1565 info->rgknbuffer + dke->nextsub - 0x20,
1566 info);
1569 if (dke->next != -1 &&
1570 ((dke->next - 0x20) < info->rgknsize) &&
1571 (dke->next > 0x20)) {
1572 _w95_walkrgkn(prevkey,
1573 info->rgknbuffer + dke->next - 0x20,
1574 info);
1577 return;
1581 /******************************************************************************
1582 * _w95_loadreg [Internal]
1584 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1586 HFILE hfd;
1587 char magic[5];
1588 unsigned long where,version,rgdbsection,end;
1589 struct _w95_info info;
1590 OFSTRUCT ofs;
1591 BY_HANDLE_FILE_INFORMATION hfdinfo;
1593 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1594 hfd=OpenFile(fn,&ofs,OF_READ);
1595 if (hfd==HFILE_ERROR)
1596 return;
1597 magic[4]=0;
1598 if (4!=_lread(hfd,magic,4))
1599 return;
1600 if (strcmp(magic,"CREG")) {
1601 WARN_(reg)("%s is not a w95 registry.\n",fn);
1602 return;
1604 if (4!=_lread(hfd,&version,4))
1605 return;
1606 if (4!=_lread(hfd,&rgdbsection,4))
1607 return;
1608 if (-1==_llseek(hfd,0x20,SEEK_SET))
1609 return;
1610 if (4!=_lread(hfd,magic,4))
1611 return;
1612 if (strcmp(magic,"RGKN")) {
1613 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1614 return;
1617 /* STEP 1: Keylink structures */
1618 if (-1==_llseek(hfd,0x40,SEEK_SET))
1619 return;
1620 where = 0x40;
1621 end = rgdbsection;
1623 info.rgknsize = end - where;
1624 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1625 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1626 return;
1628 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1629 return;
1631 end = hfdinfo.nFileSizeLow;
1632 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1634 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1635 return;
1637 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1638 info.rgdbsize = end - rgdbsection;
1640 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1641 return;
1642 _lclose(hfd);
1644 _w95_walkrgkn(lpkey, NULL, &info);
1646 free (info.rgdbbuffer);
1647 free (info.rgknbuffer);
1651 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1654 reghack - windows 3.11 registry data format demo program.
1656 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1657 a combined hash table and tree description, and finally a text table.
1659 The header is obvious from the struct header. The taboff1 and taboff2
1660 fields are always 0x20, and their usage is unknown.
1662 The 8-byte entry table has various entry types.
1664 tabent[0] is a root index. The second word has the index of the root of
1665 the directory.
1666 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1667 the index of the key/value that has that hash. Data with the same
1668 hash value are on a circular list. The other three words in the
1669 hash entry are always zero.
1670 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1671 entry: dirent and keyent/valent. They are identified by context.
1672 tabent[freeidx] is the first free entry. The first word in a free entry
1673 is the index of the next free entry. The last has 0 as a link.
1674 The other three words in the free list are probably irrelevant.
1676 Entries in text table are preceeded by a word at offset-2. This word
1677 has the value (2*index)+1, where index is the referring keyent/valent
1678 entry in the table. I have no suggestion for the 2* and the +1.
1679 Following the word, there are N bytes of data, as per the keyent/valent
1680 entry length. The offset of the keyent/valent entry is from the start
1681 of the text table to the first data byte.
1683 This information is not available from Microsoft. The data format is
1684 deduced from the reg.dat file by me. Mistakes may
1685 have been made. I claim no rights and give no guarantees for this program.
1687 Tor Sjøwall, tor@sn.no
1690 /* reg.dat header format */
1691 struct _w31_header {
1692 char cookie[8]; /* 'SHCC3.10' */
1693 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1694 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1695 unsigned long tabcnt; /* number of entries in index table */
1696 unsigned long textoff; /* offset of text part */
1697 unsigned long textsize; /* byte size of text part */
1698 unsigned short hashsize; /* hash size */
1699 unsigned short freeidx; /* free index */
1702 /* generic format of table entries */
1703 struct _w31_tabent {
1704 unsigned short w0, w1, w2, w3;
1707 /* directory tabent: */
1708 struct _w31_dirent {
1709 unsigned short sibling_idx; /* table index of sibling dirent */
1710 unsigned short child_idx; /* table index of child dirent */
1711 unsigned short key_idx; /* table index of key keyent */
1712 unsigned short value_idx; /* table index of value valent */
1715 /* key tabent: */
1716 struct _w31_keyent {
1717 unsigned short hash_idx; /* hash chain index for string */
1718 unsigned short refcnt; /* reference count */
1719 unsigned short length; /* length of string */
1720 unsigned short string_off; /* offset of string in text table */
1723 /* value tabent: */
1724 struct _w31_valent {
1725 unsigned short hash_idx; /* hash chain index for string */
1726 unsigned short refcnt; /* reference count */
1727 unsigned short length; /* length of string */
1728 unsigned short string_off; /* offset of string in text table */
1731 /* recursive helper function to display a directory tree */
1732 void
1733 __w31_dumptree( unsigned short idx,
1734 unsigned char *txt,
1735 struct _w31_tabent *tab,
1736 struct _w31_header *head,
1737 LPKEYSTRUCT lpkey,
1738 time_t lastmodified,
1739 int level
1741 struct _w31_dirent *dir;
1742 struct _w31_keyent *key;
1743 struct _w31_valent *val;
1744 LPKEYSTRUCT xlpkey = NULL;
1745 LPWSTR name,value;
1746 static char tail[400];
1748 while (idx!=0) {
1749 dir=(struct _w31_dirent*)&tab[idx];
1751 if (dir->key_idx) {
1752 key = (struct _w31_keyent*)&tab[dir->key_idx];
1754 memcpy(tail,&txt[key->string_off],key->length);
1755 tail[key->length]='\0';
1756 /* all toplevel entries AND the entries in the
1757 * toplevel subdirectory belong to \SOFTWARE\Classes
1759 if (!level && !lstrcmpA(tail,".classes")) {
1760 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1761 idx=dir->sibling_idx;
1762 continue;
1764 name=strdupA2W(tail);
1766 xlpkey=_find_or_add_key(lpkey,name);
1768 /* only add if leaf node or valued node */
1769 if (dir->value_idx!=0||dir->child_idx==0) {
1770 if (dir->value_idx) {
1771 val=(struct _w31_valent*)&tab[dir->value_idx];
1772 memcpy(tail,&txt[val->string_off],val->length);
1773 tail[val->length]='\0';
1774 value=strdupA2W(tail);
1775 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1778 } else {
1779 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1781 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1782 idx=dir->sibling_idx;
1787 /******************************************************************************
1788 * _w31_loadreg [Internal]
1790 void _w31_loadreg(void) {
1791 HFILE hf;
1792 struct _w31_header head;
1793 struct _w31_tabent *tab;
1794 unsigned char *txt;
1795 int len;
1796 OFSTRUCT ofs;
1797 BY_HANDLE_FILE_INFORMATION hfinfo;
1798 time_t lastmodified;
1799 LPKEYSTRUCT lpkey;
1801 TRACE_(reg)("(void)\n");
1803 hf = OpenFile("reg.dat",&ofs,OF_READ);
1804 if (hf==HFILE_ERROR)
1805 return;
1807 /* read & dump header */
1808 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1809 ERR_(reg)("reg.dat is too short.\n");
1810 _lclose(hf);
1811 return;
1813 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1814 ERR_(reg)("reg.dat has bad signature.\n");
1815 _lclose(hf);
1816 return;
1819 len = head.tabcnt * sizeof(struct _w31_tabent);
1820 /* read and dump index table */
1821 tab = xmalloc(len);
1822 if (len!=_lread(hf,tab,len)) {
1823 ERR_(reg)("couldn't read %d bytes.\n",len);
1824 free(tab);
1825 _lclose(hf);
1826 return;
1829 /* read text */
1830 txt = xmalloc(head.textsize);
1831 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1832 ERR_(reg)("couldn't seek to textblock.\n");
1833 free(tab);
1834 free(txt);
1835 _lclose(hf);
1836 return;
1838 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1839 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1840 free(tab);
1841 free(txt);
1842 _lclose(hf);
1843 return;
1846 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1847 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1848 free(tab);
1849 free(txt);
1850 _lclose(hf);
1851 return;
1853 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1854 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1855 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1856 free(tab);
1857 free(txt);
1858 _lclose(hf);
1859 return;
1863 /**********************************************************************************
1864 * SHELL_LoadRegistry [Internal]
1866 void SHELL_LoadRegistry( void )
1868 char *fn, *home;
1869 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1870 HKEY hkey;
1872 TRACE_(reg)("(void)\n");
1874 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1875 HKU = lookup_hkey(HKEY_USERS);
1876 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1878 /* Load windows 3.1 entries */
1879 _w31_loadreg();
1880 /* Load windows 95 entries */
1881 _w95_loadreg("C:\\system.1st", HKLM);
1882 _w95_loadreg("system.dat", HKLM);
1883 _w95_loadreg("user.dat", HKU);
1886 * Load the global HKU hive directly from /usr/local/etc
1888 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1891 * Load the global machine defaults directly form /usr/local/etc
1893 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1896 * Load the user saved registries
1898 if ((home = getenv( "HOME" )))
1901 * Load user's personal versions of global HKU/.Default keys
1903 fn=(char*)xmalloc(
1904 strlen(home)+
1905 strlen(WINE_PREFIX)+
1906 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1908 strcpy(fn, home);
1909 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1910 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1911 free(fn);
1914 * Load HKCU, attempt to get the registry location from the config
1915 * file first, if exist, load and keep going.
1917 fn = xmalloc( MAX_PATHNAME_LEN );
1918 if ( PROFILE_GetWineIniString(
1919 "Registry",
1920 "UserFileName",
1921 "",
1922 fn,
1923 MAX_PATHNAME_LEN - 1))
1925 _wine_loadreg(HKCU,fn,0);
1927 free (fn);
1929 fn=(char*)xmalloc(
1930 strlen(home)+
1931 strlen(WINE_PREFIX)+
1932 strlen(SAVE_CURRENT_USER)+2);
1934 strcpy(fn, home);
1935 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1936 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
1937 free(fn);
1940 * Load HKLM, attempt to get the registry location from the config
1941 * file first, if exist, load and keep going.
1943 fn = xmalloc ( MAX_PATHNAME_LEN);
1944 if ( PROFILE_GetWineIniString(
1945 "Registry",
1946 "LocalMachineFileName",
1947 "",
1948 fn,
1949 MAX_PATHNAME_LEN - 1))
1951 _wine_loadreg(HKLM, fn, 0);
1953 free(fn);
1955 fn=(char*)xmalloc(
1956 strlen(home)+
1957 strlen(WINE_PREFIX)+
1958 strlen(SAVE_LOCAL_MACHINE)+2);
1960 strcpy(fn,home);
1961 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1962 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
1963 free(fn);
1965 else
1967 WARN_(reg)("Failed to get homedirectory of UID %d.\n",getuid());
1971 * Obtain the handle of the HKU\.Default key.
1972 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1974 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1975 lpkey = lookup_hkey(hkey);
1976 if(!lpkey)
1977 WARN_(reg)("Could not create global user default key\n");
1978 else
1979 _copy_registry(lpkey, HKCU );
1981 RegCloseKey(hkey);
1984 * Since HKU is built from the global HKU and the local user HKU file we must
1985 * flush the HKU tree we have built at this point otherwise the part brought
1986 * in from the global HKU is saved into the local HKU. To avoid this
1987 * useless dupplication of HKU keys we reread the local HKU key.
1990 /* Allways flush the HKU hive and reload it only with user's personal HKU */
1991 _flush_registry(HKU);
1993 /* Reload user's local HKU hive */
1994 if (home)
1996 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
1997 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
1999 strcpy(fn,home);
2000 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2002 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2004 free(fn);
2008 * Make sure the update mode is there
2010 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2012 DWORD junk,type,len;
2013 char data[5];
2015 len=4;
2016 if (( RegQueryValueExA(
2017 hkey,
2018 VAL_SAVEUPDATED,
2019 &junk,
2020 &type,
2021 data,
2022 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2024 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2027 RegCloseKey(hkey);
2032 /********************* API FUNCTIONS ***************************************/
2034 * Open Keys.
2036 * All functions are stubs to RegOpenKeyEx32W where all the
2037 * magic happens.
2039 * Callpath:
2040 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2041 * RegOpenKey32W -> RegOpenKeyEx32W
2045 /******************************************************************************
2046 * RegOpenKeyEx32W [ADVAPI32.150]
2047 * Opens the specified key
2049 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2051 * PARAMS
2052 * hkey [I] Handle of open key
2053 * lpszSubKey [I] Name of subkey to open
2054 * dwReserved [I] Reserved - must be zero
2055 * samDesired [I] Security access mask
2056 * retkey [O] Address of handle of open key
2058 * RETURNS
2059 * Success: ERROR_SUCCESS
2060 * Failure: Error code
2062 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2063 REGSAM samDesired, LPHKEY retkey )
2065 LPKEYSTRUCT lpNextKey,lpxkey;
2066 LPWSTR *wps;
2067 int wpc,i;
2069 TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2070 samDesired,retkey);
2072 lpNextKey = lookup_hkey( hkey );
2073 if (!lpNextKey)
2074 return ERROR_INVALID_HANDLE;
2076 if (!lpszSubKey || !*lpszSubKey) {
2077 /* Either NULL or pointer to empty string, so return a new handle
2078 to the original hkey */
2079 currenthandle += 2;
2080 add_handle(currenthandle,lpNextKey,samDesired);
2081 *retkey=currenthandle;
2082 return ERROR_SUCCESS;
2085 if (lpszSubKey[0] == '\\') {
2086 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2087 return ERROR_BAD_PATHNAME;
2090 split_keypath(lpszSubKey,&wps,&wpc);
2091 i = 0;
2092 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2093 lpxkey = lpNextKey;
2095 while (wps[i]) {
2096 lpxkey=lpNextKey->nextsub;
2097 while (lpxkey) {
2098 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2099 break;
2101 lpxkey=lpxkey->next;
2104 if (!lpxkey) {
2105 TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2106 FREE_KEY_PATH;
2107 return ERROR_FILE_NOT_FOUND;
2109 i++;
2110 lpNextKey = lpxkey;
2113 currenthandle += 2;
2114 add_handle(currenthandle,lpxkey,samDesired);
2115 *retkey = currenthandle;
2116 TRACE_(reg)(" Returning %x\n", currenthandle);
2117 FREE_KEY_PATH;
2118 return ERROR_SUCCESS;
2122 /******************************************************************************
2123 * RegOpenKeyEx32A [ADVAPI32.149]
2125 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2126 REGSAM samDesired, LPHKEY retkey )
2128 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2129 DWORD ret;
2131 TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2132 samDesired,retkey);
2133 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2134 free(lpszSubKeyW);
2135 return ret;
2139 /******************************************************************************
2140 * RegOpenKey32W [ADVAPI32.151]
2142 * PARAMS
2143 * hkey [I] Handle of open key
2144 * lpszSubKey [I] Address of name of subkey to open
2145 * retkey [O] Address of handle of open key
2147 * RETURNS
2148 * Success: ERROR_SUCCESS
2149 * Failure: Error code
2151 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2153 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2154 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2158 /******************************************************************************
2159 * RegOpenKey32A [ADVAPI32.148]
2161 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2163 DWORD ret;
2164 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2165 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2166 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2167 free(lpszSubKeyW);
2168 return ret;
2172 /******************************************************************************
2173 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2175 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2177 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2178 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2183 * Create keys
2185 * All those functions convert their respective
2186 * arguments and call RegCreateKeyExW at the end.
2188 * We stay away from the Ex functions as long as possible because there are
2189 * differences in the return values
2191 * Callpath:
2192 * RegCreateKeyEx32A \
2193 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2197 /******************************************************************************
2198 * RegCreateKeyEx32W [ADVAPI32.131]
2200 * PARAMS
2201 * hkey [I] Handle of an open key
2202 * lpszSubKey [I] Address of subkey name
2203 * dwReserved [I] Reserved - must be 0
2204 * lpszClass [I] Address of class string
2205 * fdwOptions [I] Special options flag
2206 * samDesired [I] Desired security access
2207 * lpSecAttribs [I] Address of key security structure
2208 * retkey [O] Address of buffer for opened handle
2209 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2211 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2212 DWORD dwReserved, LPWSTR lpszClass,
2213 DWORD fdwOptions, REGSAM samDesired,
2214 LPSECURITY_ATTRIBUTES lpSecAttribs,
2215 LPHKEY retkey, LPDWORD lpDispos )
2217 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2218 LPWSTR *wps;
2219 int wpc,i;
2221 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2222 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2223 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2225 lpNextKey = lookup_hkey(hkey);
2226 if (!lpNextKey)
2227 return ERROR_INVALID_HANDLE;
2229 /* Check for valid options */
2230 switch(fdwOptions) {
2231 case REG_OPTION_NON_VOLATILE:
2232 case REG_OPTION_VOLATILE:
2233 case REG_OPTION_BACKUP_RESTORE:
2234 break;
2235 default:
2236 return ERROR_INVALID_PARAMETER;
2239 /* Sam has to be a combination of the following */
2240 if (!(samDesired &
2241 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2242 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2243 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2244 return ERROR_INVALID_PARAMETER;
2246 if (!lpszSubKey || !*lpszSubKey) {
2247 currenthandle += 2;
2248 add_handle(currenthandle,lpNextKey,samDesired);
2249 *retkey=currenthandle;
2250 TRACE_(reg)("Returning %x\n", currenthandle);
2251 lpNextKey->flags|=REG_OPTION_TAINTED;
2252 return ERROR_SUCCESS;
2255 if (lpszSubKey[0] == '\\') {
2256 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2257 return ERROR_BAD_PATHNAME;
2260 split_keypath(lpszSubKey,&wps,&wpc);
2261 i = 0;
2262 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2263 lpxkey = lpNextKey;
2264 while (wps[i]) {
2265 lpxkey=lpNextKey->nextsub;
2266 while (lpxkey) {
2267 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2268 break;
2269 lpxkey=lpxkey->next;
2271 if (!lpxkey)
2272 break;
2273 i++;
2274 lpNextKey = lpxkey;
2276 if (lpxkey) {
2277 currenthandle += 2;
2278 add_handle(currenthandle,lpxkey,samDesired);
2279 lpxkey->flags |= REG_OPTION_TAINTED;
2280 *retkey = currenthandle;
2281 TRACE_(reg)("Returning %x\n", currenthandle);
2282 if (lpDispos)
2283 *lpDispos = REG_OPENED_EXISTING_KEY;
2284 FREE_KEY_PATH;
2285 return ERROR_SUCCESS;
2288 /* Good. Now the hard part */
2289 while (wps[i]) {
2290 lplpPrevKey = &(lpNextKey->nextsub);
2291 lpxkey = *lplpPrevKey;
2292 while (lpxkey) {
2293 lplpPrevKey = &(lpxkey->next);
2294 lpxkey = *lplpPrevKey;
2296 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2297 if (!*lplpPrevKey) {
2298 FREE_KEY_PATH;
2299 TRACE_(reg)("Returning OUTOFMEMORY\n");
2300 return ERROR_OUTOFMEMORY;
2302 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2303 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2304 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2305 (*lplpPrevKey)->next = NULL;
2306 (*lplpPrevKey)->nextsub = NULL;
2307 (*lplpPrevKey)->values = NULL;
2308 (*lplpPrevKey)->nrofvalues = 0;
2309 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2310 if (lpszClass)
2311 (*lplpPrevKey)->class = strdupW(lpszClass);
2312 else
2313 (*lplpPrevKey)->class = NULL;
2314 lpNextKey = *lplpPrevKey;
2315 i++;
2317 currenthandle += 2;
2318 add_handle(currenthandle,lpNextKey,samDesired);
2320 /*FIXME: flag handling correct? */
2321 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2322 if (lpszClass)
2323 lpNextKey->class = strdupW(lpszClass);
2324 else
2325 lpNextKey->class = NULL;
2326 *retkey = currenthandle;
2327 TRACE_(reg)("Returning %x\n", currenthandle);
2328 if (lpDispos)
2329 *lpDispos = REG_CREATED_NEW_KEY;
2330 FREE_KEY_PATH;
2331 return ERROR_SUCCESS;
2335 /******************************************************************************
2336 * RegCreateKeyEx32A [ADVAPI32.130]
2338 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2339 LPSTR lpszClass, DWORD fdwOptions,
2340 REGSAM samDesired,
2341 LPSECURITY_ATTRIBUTES lpSecAttribs,
2342 LPHKEY retkey, LPDWORD lpDispos )
2344 LPWSTR lpszSubKeyW, lpszClassW;
2345 DWORD ret;
2347 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2348 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2349 retkey,lpDispos);
2351 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2352 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2354 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2355 fdwOptions, samDesired, lpSecAttribs, retkey,
2356 lpDispos );
2358 if(lpszSubKeyW) free(lpszSubKeyW);
2359 if(lpszClassW) free(lpszClassW);
2361 return ret;
2365 /******************************************************************************
2366 * RegCreateKey32W [ADVAPI32.132]
2368 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2370 DWORD junk;
2371 LPKEYSTRUCT lpNextKey;
2373 TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2375 /* This check is here because the return value is different than the
2376 one from the Ex functions */
2377 lpNextKey = lookup_hkey(hkey);
2378 if (!lpNextKey)
2379 return ERROR_BADKEY;
2381 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2382 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2383 retkey, &junk);
2387 /******************************************************************************
2388 * RegCreateKey32A [ADVAPI32.129]
2390 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2392 DWORD ret;
2393 LPWSTR lpszSubKeyW;
2395 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2396 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2397 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2398 if(lpszSubKeyW) free(lpszSubKeyW);
2399 return ret;
2403 /******************************************************************************
2404 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2406 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2408 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2409 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2414 * Query Value Functions
2415 * Win32 differs between keynames and valuenames.
2416 * multiple values may belong to one key, the special value
2417 * with name NULL is the default value used by the win31
2418 * compat functions.
2420 * Callpath:
2421 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2422 * RegQueryValue32W -> RegQueryValueEx32W
2426 /******************************************************************************
2427 * RegQueryValueEx32W [ADVAPI32.158]
2428 * Retrieves type and data for a specified name associated with an open key
2430 * PARAMS
2431 * hkey [I] Handle of key to query
2432 * lpValueName [I] Name of value to query
2433 * lpdwReserved [I] Reserved - must be NULL
2434 * lpdwType [O] Address of buffer for value type. If NULL, the type
2435 * is not required.
2436 * lpbData [O] Address of data buffer. If NULL, the actual data is
2437 * not required.
2438 * lpcbData [I/O] Address of data buffer size
2440 * RETURNS
2441 * ERROR_SUCCESS: Success
2442 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2443 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2445 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPWSTR lpValueName,
2446 LPDWORD lpdwReserved, LPDWORD lpdwType,
2447 LPBYTE lpbData, LPDWORD lpcbData )
2449 LPKEYSTRUCT lpkey;
2450 int i;
2451 DWORD ret;
2453 TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2454 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2456 lpkey = lookup_hkey(hkey);
2458 if (!lpkey)
2459 return ERROR_INVALID_HANDLE;
2461 if ((lpbData && ! lpcbData) || lpdwReserved)
2462 return ERROR_INVALID_PARAMETER;
2464 /* An empty name string is equivalent to NULL */
2465 if (lpValueName && !*lpValueName)
2466 lpValueName = NULL;
2468 if (lpValueName==NULL)
2469 { /* Use key's unnamed or default value, if any */
2470 for (i=0;i<lpkey->nrofvalues;i++)
2471 if (lpkey->values[i].name==NULL)
2472 break;
2474 else
2475 { /* Search for the key name */
2476 for (i=0;i<lpkey->nrofvalues;i++)
2477 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2478 break;
2481 if (i==lpkey->nrofvalues)
2482 { TRACE_(reg)(" Key not found\n");
2483 if (lpValueName==NULL)
2484 { /* Empty keyname not found */
2485 if (lpbData)
2486 { *(WCHAR*)lpbData = 0;
2487 *lpcbData = 2;
2489 if (lpdwType)
2490 *lpdwType = REG_SZ;
2491 TRACE_(reg)(" Returning an empty string\n");
2492 return ERROR_SUCCESS;
2494 return ERROR_FILE_NOT_FOUND;
2497 ret = ERROR_SUCCESS;
2499 if (lpdwType) /* type required ?*/
2500 *lpdwType = lpkey->values[i].type;
2502 if (lpbData) /* data required ?*/
2503 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2504 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2505 else
2506 ret = ERROR_MORE_DATA;
2509 if (lpcbData) /* size required ?*/
2510 { *lpcbData = lpkey->values[i].len;
2513 debug_print_value ( lpbData, &lpkey->values[i]);
2515 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2517 return ret;
2521 /******************************************************************************
2522 * RegQueryValue32W [ADVAPI32.159]
2524 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2525 LPLONG lpcbData )
2527 HKEY xhkey;
2528 DWORD ret,lpdwType;
2530 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2531 lpcbData?*lpcbData:0);
2533 /* Only open subkey, if we really do descend */
2534 if (lpszSubKey && *lpszSubKey) {
2535 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2536 if (ret != ERROR_SUCCESS) {
2537 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2538 return ret;
2540 } else
2541 xhkey = hkey;
2543 lpdwType = REG_SZ;
2544 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2545 lpcbData );
2546 if (xhkey != hkey)
2547 RegCloseKey(xhkey);
2548 return ret;
2552 /******************************************************************************
2553 * RegQueryValueEx32A [ADVAPI32.157]
2555 * NOTES:
2556 * the documantation is wrong: if the buffer is to small it remains untouched
2558 * FIXME: check returnvalue (len) for an empty key
2560 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPSTR lpszValueName,
2561 LPDWORD lpdwReserved, LPDWORD lpdwType,
2562 LPBYTE lpbData, LPDWORD lpcbData )
2564 LPWSTR lpszValueNameW;
2565 LPBYTE mybuf = NULL;
2566 DWORD ret, mytype, mylen = 0;
2568 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2569 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2571 if (!lpcbData && lpbData) /* buffer without size is illegal */
2572 { return ERROR_INVALID_PARAMETER;
2575 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2577 /* get just the type first */
2578 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2580 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2581 { if(lpszValueNameW) free(lpszValueNameW);
2582 return ret;
2585 if (lpcbData) /* at least length requested? */
2586 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2587 { if (lpbData ) /* value requested? */
2588 { mylen = 2*( *lpcbData );
2589 mybuf = (LPBYTE)xmalloc( mylen );
2592 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2594 if (ret == ERROR_SUCCESS )
2595 { if ( lpbData )
2596 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2600 *lpcbData = mylen/2; /* size is in byte! */
2602 else /* no strings, call it straight */
2603 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2607 if (lpdwType) /* type when requested */
2608 { *lpdwType = mytype;
2611 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2613 if(mybuf) free(mybuf);
2614 if(lpszValueNameW) free(lpszValueNameW);
2615 return ret;
2619 /******************************************************************************
2620 * RegQueryValueEx16 [KERNEL.225]
2622 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2623 LPDWORD lpdwReserved, LPDWORD lpdwType,
2624 LPBYTE lpbData, LPDWORD lpcbData )
2626 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2627 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2628 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2629 lpbData, lpcbData );
2633 /******************************************************************************
2634 * RegQueryValue32A [ADVAPI32.156]
2636 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2637 LPLONG lpcbData )
2639 HKEY xhkey;
2640 DWORD ret, dwType;
2642 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2643 lpcbData?*lpcbData:0);
2645 if (lpszSubKey && *lpszSubKey) {
2646 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2647 if( ret != ERROR_SUCCESS )
2648 return ret;
2649 } else
2650 xhkey = hkey;
2652 dwType = REG_SZ;
2653 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2654 lpcbData );
2655 if( xhkey != hkey )
2656 RegCloseKey( xhkey );
2657 return ret;
2661 /******************************************************************************
2662 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2664 * NOTES
2665 * Is this HACK still applicable?
2667 * HACK
2668 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2669 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2670 * Aldus FH4)
2672 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2673 LPDWORD lpcbData )
2675 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2676 lpcbData?*lpcbData:0);
2678 if (lpcbData)
2679 *lpcbData &= 0xFFFF;
2680 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2685 * Setting values of Registry keys
2687 * Callpath:
2688 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2689 * RegSetValue32W -> RegSetValueEx32W
2693 /******************************************************************************
2694 * RegSetValueEx32W [ADVAPI32.170]
2695 * Sets the data and type of a value under a register key
2697 * PARAMS
2698 * hkey [I] Handle of key to set value for
2699 * lpszValueName [I] Name of value to set
2700 * dwReserved [I] Reserved - must be zero
2701 * dwType [I] Flag for value type
2702 * lpbData [I] Address of value data
2703 * cbData [I] Size of value data
2705 * RETURNS
2706 * Success: ERROR_SUCCESS
2707 * Failure: Error code
2709 * NOTES
2710 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2712 DWORD WINAPI RegSetValueExW( HKEY hkey, LPWSTR lpszValueName,
2713 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2714 DWORD cbData)
2716 LPKEYSTRUCT lpkey;
2717 int i;
2719 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2720 dwReserved, dwType, lpbData, cbData);
2722 lpkey = lookup_hkey( hkey );
2724 if (!lpkey)
2725 return ERROR_INVALID_HANDLE;
2727 lpkey->flags |= REG_OPTION_TAINTED;
2729 if (lpszValueName==NULL) {
2730 /* Sets type and name for key's unnamed or default value */
2731 for (i=0;i<lpkey->nrofvalues;i++)
2732 if (lpkey->values[i].name==NULL)
2733 break;
2734 } else {
2735 for (i=0;i<lpkey->nrofvalues;i++)
2736 if ( lpkey->values[i].name &&
2737 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2739 break;
2741 if (i==lpkey->nrofvalues) {
2742 lpkey->values = (LPKEYVALUE)xrealloc(
2743 lpkey->values,
2744 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2746 lpkey->nrofvalues++;
2747 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2749 if (lpkey->values[i].name==NULL) {
2750 if (lpszValueName)
2751 lpkey->values[i].name = strdupW(lpszValueName);
2752 else
2753 lpkey->values[i].name = NULL;
2756 if (dwType == REG_SZ)
2757 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2759 lpkey->values[i].len = cbData;
2760 lpkey->values[i].type = dwType;
2761 if (lpkey->values[i].data !=NULL)
2762 free(lpkey->values[i].data);
2763 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2764 lpkey->values[i].lastmodified = time(NULL);
2765 memcpy(lpkey->values[i].data,lpbData,cbData);
2766 return ERROR_SUCCESS;
2770 /******************************************************************************
2771 * RegSetValueEx32A [ADVAPI32.169]
2773 * NOTES
2774 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2776 DWORD WINAPI RegSetValueExA( HKEY hkey, LPSTR lpszValueName,
2777 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2778 DWORD cbData )
2780 LPBYTE buf;
2781 LPWSTR lpszValueNameW;
2782 DWORD ret;
2784 if (!lpbData)
2785 return (ERROR_INVALID_PARAMETER);
2787 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2788 dwReserved,dwType,lpbData,cbData);
2790 if ((1<<dwType) & UNICONVMASK)
2791 { if (dwType == REG_SZ)
2792 cbData = strlen ((LPCSTR)lpbData)+1;
2794 buf = (LPBYTE)xmalloc( cbData *2 );
2795 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2796 cbData=2*cbData;
2798 else
2799 buf=lpbData;
2801 if (lpszValueName)
2802 lpszValueNameW = strdupA2W(lpszValueName);
2803 else
2804 lpszValueNameW = NULL;
2806 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2808 if (lpszValueNameW)
2809 free(lpszValueNameW);
2811 if (buf!=lpbData)
2812 free(buf);
2814 return ret;
2818 /******************************************************************************
2819 * RegSetValueEx16 [KERNEL.226]
2821 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2822 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2824 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2825 dwReserved,dwType,lpbData,cbData);
2826 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2827 cbData );
2831 /******************************************************************************
2832 * RegSetValue32W [ADVAPI32.171]
2834 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2835 LPCWSTR lpszData, DWORD cbData )
2837 HKEY xhkey;
2838 DWORD ret;
2840 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2841 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2843 if (lpszSubKey && *lpszSubKey) {
2844 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2845 if (ret!=ERROR_SUCCESS)
2846 return ret;
2847 } else
2848 xhkey=hkey;
2849 if (dwType!=REG_SZ) {
2850 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2851 dwType=REG_SZ;
2853 if (cbData!=2*lstrlenW(lpszData)+2) {
2854 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2855 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2857 cbData=2*lstrlenW(lpszData)+2;
2859 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2860 if (hkey!=xhkey)
2861 RegCloseKey(xhkey);
2862 return ret;
2866 /******************************************************************************
2867 * RegSetValue32A [ADVAPI32.168]
2870 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2871 LPCSTR lpszData, DWORD cbData )
2873 DWORD ret;
2874 HKEY xhkey;
2876 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2877 if (lpszSubKey && *lpszSubKey) {
2878 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2879 if (ret!=ERROR_SUCCESS)
2880 return ret;
2881 } else
2882 xhkey=hkey;
2884 if (dwType!=REG_SZ) {
2885 TRACE_(reg)("dwType=%ld!\n",dwType);
2886 dwType=REG_SZ;
2888 if (cbData!=strlen(lpszData)+1)
2889 cbData=strlen(lpszData)+1;
2890 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2891 if (xhkey!=hkey)
2892 RegCloseKey(xhkey);
2893 return ret;
2897 /******************************************************************************
2898 * RegSetValue16 [KERNEL.221] [SHELL.5]
2900 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2901 LPCSTR lpszData, DWORD cbData )
2903 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2904 debugstr_a(lpszData),cbData);
2905 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2910 * Key Enumeration
2912 * Callpath:
2913 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2914 * RegEnumKey32W -> RegEnumKeyEx32W
2918 /******************************************************************************
2919 * RegEnumKeyEx32W [ADVAPI32.139]
2921 * PARAMS
2922 * hkey [I] Handle to key to enumerate
2923 * iSubKey [I] Index of subkey to enumerate
2924 * lpszName [O] Buffer for subkey name
2925 * lpcchName [O] Size of subkey buffer
2926 * lpdwReserved [I] Reserved
2927 * lpszClass [O] Buffer for class string
2928 * lpcchClass [O] Size of class buffer
2929 * ft [O] Time key last written to
2931 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2932 LPDWORD lpcchName, LPDWORD lpdwReserved,
2933 LPWSTR lpszClass, LPDWORD lpcchClass,
2934 FILETIME *ft )
2936 LPKEYSTRUCT lpkey,lpxkey;
2938 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2939 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2941 lpkey = lookup_hkey( hkey );
2942 if (!lpkey)
2943 return ERROR_INVALID_HANDLE;
2945 if (!lpkey->nextsub)
2946 return ERROR_NO_MORE_ITEMS;
2947 lpxkey=lpkey->nextsub;
2949 /* Traverse the subkeys */
2950 while (iSubkey && lpxkey) {
2951 iSubkey--;
2952 lpxkey=lpxkey->next;
2955 if (iSubkey || !lpxkey)
2956 return ERROR_NO_MORE_ITEMS;
2957 if (lstrlenW(lpxkey->keyname)+1>*lpcchName)
2958 return ERROR_MORE_DATA;
2959 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
2961 if (*lpcchName)
2962 *lpcchName = lstrlenW(lpszName);
2964 if (lpszClass) {
2965 /* FIXME: what should we write into it? */
2966 *lpszClass = 0;
2967 *lpcchClass = 2;
2969 return ERROR_SUCCESS;
2973 /******************************************************************************
2974 * RegEnumKey32W [ADVAPI32.140]
2976 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2977 DWORD lpcchName )
2979 FILETIME ft;
2981 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2982 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2986 /******************************************************************************
2987 * RegEnumKeyEx32A [ADVAPI32.138]
2989 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2990 LPDWORD lpcchName, LPDWORD lpdwReserved,
2991 LPSTR lpszClass, LPDWORD lpcchClass,
2992 FILETIME *ft )
2994 DWORD ret,lpcchNameW,lpcchClassW;
2995 LPWSTR lpszNameW,lpszClassW;
2998 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2999 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3001 if (lpszName) {
3002 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3003 lpcchNameW = *lpcchName;
3004 } else {
3005 lpszNameW = NULL;
3006 lpcchNameW = 0;
3008 if (lpszClass) {
3009 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3010 lpcchClassW = *lpcchClass;
3011 } else {
3012 lpszClassW =0;
3013 lpcchClassW=0;
3015 ret=RegEnumKeyExW(
3016 hkey,
3017 iSubkey,
3018 lpszNameW,
3019 &lpcchNameW,
3020 lpdwReserved,
3021 lpszClassW,
3022 &lpcchClassW,
3025 if (ret==ERROR_SUCCESS) {
3026 lstrcpyWtoA(lpszName,lpszNameW);
3027 *lpcchName=strlen(lpszName);
3028 if (lpszClassW) {
3029 lstrcpyWtoA(lpszClass,lpszClassW);
3030 *lpcchClass=strlen(lpszClass);
3033 if (lpszNameW)
3034 free(lpszNameW);
3035 if (lpszClassW)
3036 free(lpszClassW);
3037 return ret;
3041 /******************************************************************************
3042 * RegEnumKey32A [ADVAPI32.137]
3044 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3045 DWORD lpcchName )
3047 FILETIME ft;
3049 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3050 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3051 NULL, &ft );
3055 /******************************************************************************
3056 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3058 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3059 DWORD lpcchName )
3061 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3062 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3067 * Enumerate Registry Values
3069 * Callpath:
3070 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3074 /******************************************************************************
3075 * RegEnumValue32W [ADVAPI32.142]
3077 * PARAMS
3078 * hkey [I] Handle to key to query
3079 * iValue [I] Index of value to query
3080 * lpszValue [O] Value string
3081 * lpcchValue [I/O] Size of value buffer (in wchars)
3082 * lpdReserved [I] Reserved
3083 * lpdwType [O] Type code
3084 * lpbData [O] Value data
3085 * lpcbData [I/O] Size of data buffer (in bytes)
3087 * Note: wide character functions that take and/or return "character counts"
3088 * use TCHAR (that is unsigned short or char) not byte counts.
3090 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3091 LPDWORD lpcchValue, LPDWORD lpdReserved,
3092 LPDWORD lpdwType, LPBYTE lpbData,
3093 LPDWORD lpcbData )
3095 LPKEYSTRUCT lpkey;
3096 LPKEYVALUE val;
3098 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3099 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3101 lpkey = lookup_hkey( hkey );
3103 if (!lpcbData && lpbData)
3104 return ERROR_INVALID_PARAMETER;
3106 if (!lpkey)
3107 return ERROR_INVALID_HANDLE;
3109 if (lpkey->nrofvalues <= iValue)
3110 return ERROR_NO_MORE_ITEMS;
3112 val = &(lpkey->values[iValue]);
3114 if (val->name) {
3115 if (lstrlenW(val->name)+1>*lpcchValue) {
3116 *lpcchValue = lstrlenW(val->name)+1;
3117 return ERROR_MORE_DATA;
3119 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3120 *lpcchValue=lstrlenW(val->name);
3121 } else {
3122 *lpszValue = 0;
3123 *lpcchValue = 0;
3126 /* Can be NULL if the type code is not required */
3127 if (lpdwType)
3128 *lpdwType = val->type;
3130 if (lpbData) {
3131 if (val->len>*lpcbData)
3132 return ERROR_MORE_DATA;
3133 memcpy(lpbData,val->data,val->len);
3134 *lpcbData = val->len;
3137 debug_print_value ( val->data, val );
3138 return ERROR_SUCCESS;
3142 /******************************************************************************
3143 * RegEnumValue32A [ADVAPI32.141]
3145 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3146 LPDWORD lpcchValue, LPDWORD lpdReserved,
3147 LPDWORD lpdwType, LPBYTE lpbData,
3148 LPDWORD lpcbData )
3150 LPWSTR lpszValueW;
3151 LPBYTE lpbDataW;
3152 DWORD ret,lpcbDataW;
3153 DWORD dwType;
3155 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3156 lpdReserved,lpdwType,lpbData,lpcbData);
3158 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3159 if (lpbData) {
3160 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3161 lpcbDataW = *lpcbData;
3162 } else
3163 lpbDataW = NULL;
3165 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3166 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3168 if (lpdwType)
3169 *lpdwType = dwType;
3171 if (ret==ERROR_SUCCESS) {
3172 lstrcpyWtoA(lpszValue,lpszValueW);
3173 if (lpbData) {
3174 if ((1<<dwType) & UNICONVMASK) {
3175 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3176 } else {
3177 if (lpcbDataW > *lpcbData)
3178 ret = ERROR_MORE_DATA;
3179 else
3180 memcpy(lpbData,lpbDataW,lpcbDataW);
3182 *lpcbData = lpcbDataW;
3185 if (lpbDataW) free(lpbDataW);
3186 if (lpszValueW) free(lpszValueW);
3187 return ret;
3191 /******************************************************************************
3192 * RegEnumValue16 [KERNEL.223]
3194 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3195 LPDWORD lpcchValue, LPDWORD lpdReserved,
3196 LPDWORD lpdwType, LPBYTE lpbData,
3197 LPDWORD lpcbData )
3199 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3200 lpdReserved,lpdwType,lpbData,lpcbData);
3201 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3202 lpdwType, lpbData, lpcbData );
3206 /******************************************************************************
3207 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3208 * Releases the handle of the specified key
3210 * PARAMS
3211 * hkey [I] Handle of key to close
3213 * RETURNS
3214 * Success: ERROR_SUCCESS
3215 * Failure: Error code
3217 DWORD WINAPI RegCloseKey( HKEY hkey )
3219 TRACE_(reg)("(%x)\n",hkey);
3221 /* The standard handles are allowed to succeed, even though they are not
3222 closed */
3223 if (is_standard_hkey(hkey))
3224 return ERROR_SUCCESS;
3226 return remove_handle(hkey);
3231 * Delete registry key
3233 * Callpath:
3234 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3238 /******************************************************************************
3239 * RegDeleteKey32W [ADVAPI32.134]
3241 * PARAMS
3242 * hkey [I] Handle to open key
3243 * lpszSubKey [I] Name of subkey to delete
3245 * RETURNS
3246 * Success: ERROR_SUCCESS
3247 * Failure: Error code
3249 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPWSTR lpszSubKey )
3251 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3252 LPWSTR *wps;
3253 int wpc,i;
3255 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3257 lpNextKey = lookup_hkey(hkey);
3258 if (!lpNextKey)
3259 return ERROR_INVALID_HANDLE;
3261 /* Subkey param cannot be NULL */
3262 if (!lpszSubKey || !*lpszSubKey)
3263 return ERROR_BADKEY;
3265 /* We need to know the previous key in the hier. */
3266 split_keypath(lpszSubKey,&wps,&wpc);
3267 i = 0;
3268 lpxkey = lpNextKey;
3269 while (i<wpc-1) {
3270 lpxkey=lpNextKey->nextsub;
3271 while (lpxkey) {
3272 TRACE_(reg)(" Scanning [%s]\n",
3273 debugstr_w(lpxkey->keyname));
3274 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3275 break;
3276 lpxkey=lpxkey->next;
3278 if (!lpxkey) {
3279 FREE_KEY_PATH;
3280 TRACE_(reg)(" Not found.\n");
3281 /* not found is success */
3282 return ERROR_SUCCESS;
3284 i++;
3285 lpNextKey = lpxkey;
3287 lpxkey = lpNextKey->nextsub;
3288 lplpPrevKey = &(lpNextKey->nextsub);
3289 while (lpxkey) {
3290 TRACE_(reg)(" Scanning [%s]\n",
3291 debugstr_w(lpxkey->keyname));
3292 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3293 break;
3294 lplpPrevKey = &(lpxkey->next);
3295 lpxkey = lpxkey->next;
3298 if (!lpxkey) {
3299 FREE_KEY_PATH;
3300 WARN_(reg)(" Not found.\n");
3301 return ERROR_FILE_NOT_FOUND;
3304 if (lpxkey->nextsub) {
3305 FREE_KEY_PATH;
3306 WARN_(reg)(" Not empty.\n");
3307 return ERROR_CANTWRITE;
3309 *lplpPrevKey = lpxkey->next;
3310 free(lpxkey->keyname);
3311 if (lpxkey->class)
3312 free(lpxkey->class);
3313 if (lpxkey->values)
3314 free(lpxkey->values);
3315 free(lpxkey);
3316 FREE_KEY_PATH;
3317 TRACE_(reg)(" Done.\n");
3318 return ERROR_SUCCESS;
3322 /******************************************************************************
3323 * RegDeleteKey32A [ADVAPI32.133]
3325 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3327 LPWSTR lpszSubKeyW;
3328 DWORD ret;
3330 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3331 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3332 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3333 if(lpszSubKeyW) free(lpszSubKeyW);
3334 return ret;
3338 /******************************************************************************
3339 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3341 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3343 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3344 return RegDeleteKeyA( hkey, lpszSubKey );
3349 * Delete registry value
3351 * Callpath:
3352 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3356 /******************************************************************************
3357 * RegDeleteValue32W [ADVAPI32.136]
3359 * PARAMS
3360 * hkey [I]
3361 * lpszValue [I]
3363 * RETURNS
3365 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPWSTR lpszValue )
3367 DWORD i;
3368 LPKEYSTRUCT lpkey;
3369 LPKEYVALUE val;
3371 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3373 lpkey = lookup_hkey( hkey );
3374 if (!lpkey)
3375 return ERROR_INVALID_HANDLE;
3377 if (lpszValue) {
3378 for (i=0;i<lpkey->nrofvalues;i++)
3379 if ( lpkey->values[i].name &&
3380 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3382 break;
3383 } else {
3384 for (i=0;i<lpkey->nrofvalues;i++)
3385 if (lpkey->values[i].name==NULL)
3386 break;
3389 if (i == lpkey->nrofvalues)
3390 return ERROR_FILE_NOT_FOUND;
3392 val = lpkey->values+i;
3393 if (val->name) free(val->name);
3394 if (val->data) free(val->data);
3395 memcpy(
3396 lpkey->values+i,
3397 lpkey->values+i+1,
3398 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3400 lpkey->values = (LPKEYVALUE)xrealloc(
3401 lpkey->values,
3402 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3404 lpkey->nrofvalues--;
3405 return ERROR_SUCCESS;
3409 /******************************************************************************
3410 * RegDeleteValue32A [ADVAPI32.135]
3412 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPSTR lpszValue )
3414 LPWSTR lpszValueW;
3415 DWORD ret;
3417 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3418 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3419 ret = RegDeleteValueW( hkey, lpszValueW );
3420 if(lpszValueW) free(lpszValueW);
3421 return ret;
3425 /******************************************************************************
3426 * RegDeleteValue16 [KERNEL.222]
3428 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3430 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3431 return RegDeleteValueA( hkey, lpszValue );
3435 /******************************************************************************
3436 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3437 * Writes key to registry
3439 * PARAMS
3440 * hkey [I] Handle of key to write
3442 * RETURNS
3443 * Success: ERROR_SUCCESS
3444 * Failure: Error code
3446 DWORD WINAPI RegFlushKey( HKEY hkey )
3448 LPKEYSTRUCT lpkey;
3449 BOOL ret;
3451 TRACE_(reg)("(%x)\n", hkey);
3453 lpkey = lookup_hkey( hkey );
3454 if (!lpkey)
3455 return ERROR_BADKEY;
3457 ERR_(reg)("What is the correct filename?\n");
3459 ret = _savereg( lpkey, "foo.bar", TRUE);
3461 if( ret ) {
3462 return ERROR_SUCCESS;
3463 } else
3464 return ERROR_UNKNOWN; /* FIXME */
3468 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3471 /******************************************************************************
3472 * RegQueryInfoKey32W [ADVAPI32.153]
3474 * PARAMS
3475 * hkey [I] Handle to key to query
3476 * lpszClass [O] Buffer for class string
3477 * lpcchClass [O] Size of class string buffer
3478 * lpdwReserved [I] Reserved
3479 * lpcSubKeys [I] Buffer for number of subkeys
3480 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3481 * lpcchMaxClass [O] Buffer for longest class string length
3482 * lpcValues [O] Buffer for number of value entries
3483 * lpcchMaxValueName [O] Buffer for longest value name length
3484 * lpccbMaxValueData [O] Buffer for longest value data length
3485 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3486 * ft
3487 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3488 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3489 * lpcchClass is NULL
3490 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3491 * (it's hard to test validity, so test !NULL instead)
3493 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3494 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3495 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3496 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3497 LPDWORD lpcchMaxValueName,
3498 LPDWORD lpccbMaxValueData,
3499 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3501 LPKEYSTRUCT lpkey,lpxkey;
3502 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3503 int i;
3505 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3506 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3507 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3508 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3510 lpkey = lookup_hkey(hkey);
3511 if (!lpkey)
3512 return ERROR_INVALID_HANDLE;
3513 if (lpszClass) {
3514 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3515 return ERROR_INVALID_PARAMETER;
3517 /* either lpcchClass is valid or this is win95 and lpcchClass
3518 could be invalid */
3519 if (lpkey->class) {
3520 DWORD classLen = lstrlenW(lpkey->class);
3522 if (lpcchClass && classLen+1>*lpcchClass) {
3523 *lpcchClass=classLen+1;
3524 return ERROR_MORE_DATA;
3526 if (lpcchClass)
3527 *lpcchClass=classLen;
3528 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3529 } else {
3530 *lpszClass = 0;
3531 if (lpcchClass)
3532 *lpcchClass = 0;
3534 } else {
3535 if (lpcchClass)
3536 *lpcchClass = lstrlenW(lpkey->class);
3538 lpxkey=lpkey->nextsub;
3539 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3540 while (lpxkey) {
3541 nrofkeys++;
3542 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3543 maxsubkey=lstrlenW(lpxkey->keyname);
3544 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3545 maxclass=lstrlenW(lpxkey->class);
3546 lpxkey=lpxkey->next;
3548 for (i=0;i<lpkey->nrofvalues;i++) {
3549 LPKEYVALUE val=lpkey->values+i;
3551 if (val->name && lstrlenW(val->name)>maxvname)
3552 maxvname=lstrlenW(val->name);
3553 if (val->len>maxvdata)
3554 maxvdata=val->len;
3556 if (!maxclass) maxclass = 1;
3557 if (!maxvname) maxvname = 1;
3558 if (lpcValues)
3559 *lpcValues = lpkey->nrofvalues;
3560 if (lpcSubKeys)
3561 *lpcSubKeys = nrofkeys;
3562 if (lpcchMaxSubkey)
3563 *lpcchMaxSubkey = maxsubkey;
3564 if (lpcchMaxClass)
3565 *lpcchMaxClass = maxclass;
3566 if (lpcchMaxValueName)
3567 *lpcchMaxValueName= maxvname;
3568 if (lpccbMaxValueData)
3569 *lpccbMaxValueData= maxvdata;
3570 return ERROR_SUCCESS;
3574 /******************************************************************************
3575 * RegQueryInfoKey32A [ADVAPI32.152]
3577 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3578 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3579 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3580 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3581 LPDWORD lpccbMaxValueData,
3582 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3584 LPWSTR lpszClassW = NULL;
3585 DWORD ret;
3587 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3588 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3589 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3590 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3592 if (lpszClass) {
3593 if (lpcchClass) {
3594 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3595 } else if (VERSION_GetVersion() == WIN95) {
3596 /* win95 allows lpcchClass to be null */
3597 /* we don't know how big lpszClass is, would
3598 MAX_PATHNAME_LEN be the correct default? */
3599 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3602 } else
3603 lpszClassW = NULL;
3604 ret=RegQueryInfoKeyW(
3605 hkey,
3606 lpszClassW,
3607 lpcchClass,
3608 lpdwReserved,
3609 lpcSubKeys,
3610 lpcchMaxSubkey,
3611 lpcchMaxClass,
3612 lpcValues,
3613 lpcchMaxValueName,
3614 lpccbMaxValueData,
3615 lpcbSecurityDescriptor,
3618 if (ret==ERROR_SUCCESS && lpszClass)
3619 lstrcpyWtoA(lpszClass,lpszClassW);
3620 if (lpszClassW)
3621 free(lpszClassW);
3622 return ret;
3626 /******************************************************************************
3627 * RegConnectRegistry32W [ADVAPI32.128]
3629 * PARAMS
3630 * lpMachineName [I] Address of name of remote computer
3631 * hHey [I] Predefined registry handle
3632 * phkResult [I] Address of buffer for remote registry handle
3634 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3635 LPHKEY phkResult )
3637 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3639 if (!lpMachineName || !*lpMachineName) {
3640 /* Use the local machine name */
3641 return RegOpenKey16( hKey, "", phkResult );
3644 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3645 return ERROR_BAD_NETPATH;
3649 /******************************************************************************
3650 * RegConnectRegistry32A [ADVAPI32.127]
3652 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3654 DWORD ret;
3655 LPWSTR machineW = strdupA2W(machine);
3656 ret = RegConnectRegistryW( machineW, hkey, reskey );
3657 free(machineW);
3658 return ret;
3662 /******************************************************************************
3663 * RegGetKeySecurity [ADVAPI32.144]
3664 * Retrieves a copy of security descriptor protecting the registry key
3666 * PARAMS
3667 * hkey [I] Open handle of key to set
3668 * SecurityInformation [I] Descriptor contents
3669 * pSecurityDescriptor [O] Address of descriptor for key
3670 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3672 * RETURNS
3673 * Success: ERROR_SUCCESS
3674 * Failure: Error code
3676 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3677 SECURITY_INFORMATION SecurityInformation,
3678 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3679 LPDWORD lpcbSecurityDescriptor )
3681 LPKEYSTRUCT lpkey;
3683 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3684 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3686 lpkey = lookup_hkey( hkey );
3687 if (!lpkey)
3688 return ERROR_INVALID_HANDLE;
3690 /* FIXME: Check for valid SecurityInformation values */
3692 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3693 return ERROR_INSUFFICIENT_BUFFER;
3695 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3696 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3698 return ERROR_SUCCESS;
3702 /******************************************************************************
3703 * RegLoadKey32W [ADVAPI32.???]
3705 * PARAMS
3706 * hkey [I] Handle of open key
3707 * lpszSubKey [I] Address of name of subkey
3708 * lpszFile [I] Address of filename for registry information
3710 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3712 LPKEYSTRUCT lpkey;
3713 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3715 /* Do this check before the hkey check */
3716 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3717 return ERROR_INVALID_PARAMETER;
3719 lpkey = lookup_hkey( hkey );
3720 if (!lpkey)
3721 return ERROR_INVALID_HANDLE;
3723 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3724 debugstr_w(lpszFile));
3726 return ERROR_SUCCESS;
3730 /******************************************************************************
3731 * RegLoadKey32A [ADVAPI32.???]
3733 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3735 LONG ret;
3736 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3737 LPWSTR lpszFileW = strdupA2W(lpszFile);
3738 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3739 if(lpszFileW) free(lpszFileW);
3740 if(lpszSubKeyW) free(lpszSubKeyW);
3741 return ret;
3745 /******************************************************************************
3746 * RegNotifyChangeKeyValue [ADVAPI32.???]
3748 * PARAMS
3749 * hkey [I] Handle of key to watch
3750 * fWatchSubTree [I] Flag for subkey notification
3751 * fdwNotifyFilter [I] Changes to be reported
3752 * hEvent [I] Handle of signaled event
3753 * fAsync [I] Flag for asynchronous reporting
3755 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3756 DWORD fdwNotifyFilter, HANDLE hEvent,
3757 BOOL fAsync )
3759 LPKEYSTRUCT lpkey;
3760 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3761 hEvent,fAsync);
3763 lpkey = lookup_hkey( hkey );
3764 if (!lpkey)
3765 return ERROR_INVALID_HANDLE;
3767 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3768 hEvent,fAsync);
3770 return ERROR_SUCCESS;
3774 /******************************************************************************
3775 * RegUnLoadKey32W [ADVAPI32.173]
3777 * PARAMS
3778 * hkey [I] Handle of open key
3779 * lpSubKey [I] Address of name of subkey to unload
3781 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3783 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3784 return ERROR_SUCCESS;
3788 /******************************************************************************
3789 * RegUnLoadKey32A [ADVAPI32.172]
3791 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3793 LONG ret;
3794 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3795 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3796 if(lpSubKeyW) free(lpSubKeyW);
3797 return ret;
3801 /******************************************************************************
3802 * RegSetKeySecurity [ADVAPI32.167]
3804 * PARAMS
3805 * hkey [I] Open handle of key to set
3806 * SecurityInfo [I] Descriptor contents
3807 * pSecurityDesc [I] Address of descriptor for key
3809 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3810 PSECURITY_DESCRIPTOR pSecurityDesc )
3812 LPKEYSTRUCT lpkey;
3814 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3816 /* It seems to perform this check before the hkey check */
3817 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3818 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3819 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3820 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3821 /* Param OK */
3822 } else
3823 return ERROR_INVALID_PARAMETER;
3825 if (!pSecurityDesc)
3826 return ERROR_INVALID_PARAMETER;
3828 lpkey = lookup_hkey( hkey );
3829 if (!lpkey)
3830 return ERROR_INVALID_HANDLE;
3832 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3834 return ERROR_SUCCESS;
3838 /******************************************************************************
3839 * RegSaveKey32W [ADVAPI32.166]
3841 * PARAMS
3842 * hkey [I] Handle of key where save begins
3843 * lpFile [I] Address of filename to save to
3844 * sa [I] Address of security structure
3846 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3847 LPSECURITY_ATTRIBUTES sa )
3849 LPKEYSTRUCT lpkey;
3851 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3853 /* It appears to do this check before the hkey check */
3854 if (!lpFile || !*lpFile)
3855 return ERROR_INVALID_PARAMETER;
3857 lpkey = lookup_hkey( hkey );
3858 if (!lpkey)
3859 return ERROR_INVALID_HANDLE;
3861 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3863 return ERROR_SUCCESS;
3867 /******************************************************************************
3868 * RegSaveKey32A [ADVAPI32.165]
3870 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3871 LPSECURITY_ATTRIBUTES sa )
3873 LONG ret;
3874 LPWSTR lpFileW = strdupA2W(lpFile);
3875 ret = RegSaveKeyW( hkey, lpFileW, sa );
3876 free(lpFileW);
3877 return ret;
3881 /******************************************************************************
3882 * RegRestoreKey32W [ADVAPI32.164]
3884 * PARAMS
3885 * hkey [I] Handle of key where restore begins
3886 * lpFile [I] Address of filename containing saved tree
3887 * dwFlags [I] Optional flags
3889 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3891 LPKEYSTRUCT lpkey;
3893 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3895 /* It seems to do this check before the hkey check */
3896 if (!lpFile || !*lpFile)
3897 return ERROR_INVALID_PARAMETER;
3899 lpkey = lookup_hkey( hkey );
3900 if (!lpkey)
3901 return ERROR_INVALID_HANDLE;
3903 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3905 /* Check for file existence */
3907 return ERROR_SUCCESS;
3911 /******************************************************************************
3912 * RegRestoreKey32A [ADVAPI32.163]
3914 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3916 LONG ret;
3917 LPWSTR lpFileW = strdupA2W(lpFile);
3918 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3919 if(lpFileW) free(lpFileW);
3920 return ret;
3924 /******************************************************************************
3925 * RegReplaceKey32W [ADVAPI32.162]
3927 * PARAMS
3928 * hkey [I] Handle of open key
3929 * lpSubKey [I] Address of name of subkey
3930 * lpNewFile [I] Address of filename for file with new data
3931 * lpOldFile [I] Address of filename for backup file
3933 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3934 LPCWSTR lpOldFile )
3936 LPKEYSTRUCT lpkey;
3938 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3939 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3941 lpkey = lookup_hkey( hkey );
3942 if (!lpkey)
3943 return ERROR_INVALID_HANDLE;
3945 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3946 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3948 return ERROR_SUCCESS;
3952 /******************************************************************************
3953 * RegReplaceKey32A [ADVAPI32.161]
3955 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3956 LPCSTR lpOldFile )
3958 LONG ret;
3959 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3960 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3961 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3962 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3963 free(lpOldFileW);
3964 free(lpNewFileW);
3965 free(lpSubKeyW);
3966 return ret;