4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
15 #include <sys/types.h>
23 #include "wine/winbase16.h"
27 #include "debugtools.h"
31 DEFAULT_DEBUG_CHANNEL(profile);
33 typedef struct tagPROFILEKEY
37 struct tagPROFILEKEY *next;
40 typedef struct tagPROFILESECTION
43 struct tagPROFILEKEY *key;
44 struct tagPROFILESECTION *next;
51 PROFILESECTION *section;
59 #define N_CACHED_PROFILES 10
61 /* Cached profile files */
62 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
64 #define CurProfile (MRUProfile[0])
66 /* wine.ini config file registry root */
67 static HKEY wine_profile_key;
69 #define PROFILE_MAX_LINE_LEN 1024
71 /* Wine profile name in $HOME directory; must begin with slash */
72 static const char PROFILE_WineIniName[] = "/.winerc";
74 /* Wine profile: the profile file being used */
75 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
77 /* Check for comments in profile */
78 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
80 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
82 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
84 static const char hex[16] = "0123456789ABCDEF";
86 /***********************************************************************
89 * Copy the content of an entry into a buffer, removing quotes, and possibly
90 * translating environment variables.
92 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
100 if ((*value == '\'') || (*value == '\"'))
102 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
107 lstrcpynA( buffer, value, len );
108 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
112 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
114 if ((*p == '$') && (p[1] == '{'))
118 const char *p2 = strchr( p, '}' );
119 if (!p2) continue; /* ignore it */
120 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
121 if ((env_p = getenv( env_val )) != NULL)
124 lstrcpynA( buffer, env_p, len );
125 buffer_len = strlen( buffer );
126 buffer += buffer_len;
132 if (quote && (len > 1)) buffer--;
137 /***********************************************************************
140 * Save a profile tree to a file.
142 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
146 for ( ; section; section = section->next)
148 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
149 for (key = section->key; key; key = key->next)
151 fprintf( file, "%s", key->name );
152 if (key->value) fprintf( file, "=%s", key->value );
153 fprintf( file, "\r\n" );
159 /***********************************************************************
162 * Free a profile tree.
164 static void PROFILE_Free( PROFILESECTION *section )
166 PROFILESECTION *next_section;
167 PROFILEKEY *key, *next_key;
169 for ( ; section; section = next_section)
171 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
172 for (key = section->key; key; key = next_key)
174 next_key = key->next;
175 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
176 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
177 HeapFree( GetProcessHeap(), 0, key );
179 next_section = section->next;
180 HeapFree( GetProcessHeap(), 0, section );
184 static inline int PROFILE_isspace(char c)
186 if (isspace(c)) return 1;
187 if (c=='\r' || c==0x1a) return 1;
188 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
193 /***********************************************************************
196 * Load a profile tree from a file.
198 static PROFILESECTION *PROFILE_Load( FILE *file )
200 char buffer[PROFILE_MAX_LINE_LEN];
203 PROFILESECTION *section, *first_section;
204 PROFILESECTION **next_section;
205 PROFILEKEY *key, *prev_key, **next_key;
207 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
208 if(first_section == NULL) return NULL;
209 first_section->name = NULL;
210 first_section->key = NULL;
211 first_section->next = NULL;
212 next_section = &first_section->next;
213 next_key = &first_section->key;
216 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
220 while (*p && PROFILE_isspace(*p)) p++;
221 if (*p == '[') /* section start */
223 if (!(p2 = strrchr( p, ']' )))
225 WARN("Invalid section header at line %d: '%s'\n",
232 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
233 if(section == NULL) break;
234 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
236 section->next = NULL;
237 *next_section = section;
238 next_section = §ion->next;
239 next_key = §ion->key;
242 TRACE("New section: '%s'\n",section->name);
249 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
251 if ((p2 = strchr( p, '=' )) != NULL)
254 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
256 while (*p2 && PROFILE_isspace(*p2)) p2++;
259 if(*p || !prev_key || *prev_key->name)
261 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
262 if(key == NULL) break;
263 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
264 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
267 next_key = &key->next;
270 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
273 return first_section;
276 /* convert the .winerc file to the new format */
277 static void convert_config( FILE *in, const char *output_name )
279 char buffer[PROFILE_MAX_LINE_LEN];
283 /* create the output file, only if it doesn't exist already */
284 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
287 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
291 out = fdopen( fd, "w" );
292 fprintf( out, "WINE REGISTRY Version 2\n" );
293 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
294 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
296 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
298 while (*p && PROFILE_isspace(*p)) p++;
299 if (*p == '[') /* section start */
301 if ((p2 = strrchr( p, ']' )))
305 fprintf( out, "[%s]\n", p );
310 if (*p == ';' || *p == '#')
312 fprintf( out, "%s\n", p );
317 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
319 if ((p2 = strchr( p, '=' )) != NULL)
322 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
324 while (*p2 && PROFILE_isspace(*p2)) p2++;
329 fprintf( out, "\n" );
335 if (*p == '\\') fputc( '\\', out );
339 fprintf( out, "\" = \"" );
344 if (*p2 == '\\') fputc( '\\', out );
349 fprintf( out, "\"\n" );
355 /***********************************************************************
356 * PROFILE_DeleteSection
358 * Delete a section from a profile tree.
360 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
364 if ((*section)->name && !strcasecmp( (*section)->name, name ))
366 PROFILESECTION *to_del = *section;
367 *section = to_del->next;
369 PROFILE_Free( to_del );
372 section = &(*section)->next;
378 /***********************************************************************
381 * Delete a key from a profile tree.
383 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
384 LPCSTR section_name, LPCSTR key_name )
388 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
390 PROFILEKEY **key = &(*section)->key;
393 if (!strcasecmp( (*key)->name, key_name ))
395 PROFILEKEY *to_del = *key;
397 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
398 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
399 HeapFree( GetProcessHeap(), 0, to_del );
405 section = &(*section)->next;
411 /***********************************************************************
412 * PROFILE_DeleteAllKeys
414 * Delete all keys from a profile tree.
416 void PROFILE_DeleteAllKeys( LPCSTR section_name)
418 PROFILESECTION **section= &CurProfile->section;
421 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
423 PROFILEKEY **key = &(*section)->key;
426 PROFILEKEY *to_del = *key;
428 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
429 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
430 HeapFree( GetProcessHeap(), 0, to_del );
431 CurProfile->changed =TRUE;
434 section = &(*section)->next;
439 /***********************************************************************
442 * Find a key in a profile tree, optionally creating it.
444 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
445 const char *section_name,
446 const char *key_name, int create )
451 while (PROFILE_isspace(*section_name)) section_name++;
452 p = section_name + strlen(section_name) - 1;
453 while ((p > section_name) && PROFILE_isspace(*p)) p--;
454 seclen = p - section_name + 1;
456 while (PROFILE_isspace(*key_name)) key_name++;
457 p = key_name + strlen(key_name) - 1;
458 while ((p > key_name) && PROFILE_isspace(*p)) p--;
459 keylen = p - key_name + 1;
463 if ( ((*section)->name)
464 && (!(strncasecmp( (*section)->name, section_name, seclen )))
465 && (((*section)->name)[seclen] == '\0') )
467 PROFILEKEY **key = &(*section)->key;
470 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
471 && (((*key)->name)[keylen] == '\0') )
475 if (!create) return NULL;
476 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
477 if(*key == NULL) return NULL;
478 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
479 (*key)->value = NULL;
483 section = &(*section)->next;
485 if (!create) return NULL;
486 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
487 if(*section == NULL) return NULL;
488 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
489 (*section)->next = NULL;
490 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
491 if((*section)->key == NULL)
493 HeapFree(GetProcessHeap(), 0, *section);
496 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
497 (*section)->key->value = NULL;
498 (*section)->key->next = NULL;
499 return (*section)->key;
503 /***********************************************************************
506 * Flush the current profile to disk if changed.
508 static BOOL PROFILE_FlushFile(void)
510 char *p, buffer[MAX_PATHNAME_LEN];
511 const char *unix_name;
517 WARN("No current profile!\n");
521 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
522 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
524 /* Try to create it in $HOME/.wine */
525 /* FIXME: this will need a more general solution */
526 strcpy( buffer, get_config_dir() );
527 p = buffer + strlen(buffer);
529 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
531 file = fopen( buffer, "w" );
537 WARN("could not save profile file %s\n", CurProfile->dos_name);
541 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
542 PROFILE_Save( file, CurProfile->section );
544 CurProfile->changed = FALSE;
545 if(!stat(unix_name,&buf))
546 CurProfile->mtime=buf.st_mtime;
551 /***********************************************************************
552 * PROFILE_ReleaseFile
554 * Flush the current profile to disk and remove it from the cache.
556 static void PROFILE_ReleaseFile(void)
559 PROFILE_Free( CurProfile->section );
560 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
561 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
562 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
563 CurProfile->changed = FALSE;
564 CurProfile->section = NULL;
565 CurProfile->dos_name = NULL;
566 CurProfile->unix_name = NULL;
567 CurProfile->filename = NULL;
568 CurProfile->mtime = 0;
572 /***********************************************************************
575 * Open a profile file, checking the cached file first.
577 static BOOL PROFILE_Open( LPCSTR filename )
579 DOS_FULL_NAME full_name;
580 char buffer[MAX_PATHNAME_LEN];
581 char *newdos_name, *p;
585 PROFILE *tempProfile;
587 /* First time around */
590 for(i=0;i<N_CACHED_PROFILES;i++)
592 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
593 if(MRUProfile[i] == NULL) break;
594 MRUProfile[i]->changed=FALSE;
595 MRUProfile[i]->section=NULL;
596 MRUProfile[i]->dos_name=NULL;
597 MRUProfile[i]->unix_name=NULL;
598 MRUProfile[i]->filename=NULL;
599 MRUProfile[i]->mtime=0;
602 /* Check for a match */
604 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
605 strchr( filename, ':' ))
607 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
611 GetWindowsDirectoryA( buffer, sizeof(buffer) );
612 strcat( buffer, "\\" );
613 strcat( buffer, filename );
614 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
617 for(i=0;i<N_CACHED_PROFILES;i++)
619 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
620 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
625 tempProfile=MRUProfile[i];
627 MRUProfile[j]=MRUProfile[j-1];
628 CurProfile=tempProfile;
630 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
631 TRACE("(%s): already opened (mru=%d)\n",
634 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
640 /* Flush the old current profile */
643 /* Make the oldest profile the current one only in order to get rid of it */
644 if(i==N_CACHED_PROFILES)
646 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
647 for(i=N_CACHED_PROFILES-1;i>0;i--)
648 MRUProfile[i]=MRUProfile[i-1];
649 CurProfile=tempProfile;
651 if(CurProfile->filename) PROFILE_ReleaseFile();
653 /* OK, now that CurProfile is definitely free we assign it our new file */
654 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
655 CurProfile->dos_name = newdos_name;
656 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
658 /* Try to open the profile file, first in $HOME/.wine */
660 /* FIXME: this will need a more general solution */
661 strcpy( buffer, get_config_dir() );
662 p = buffer + strlen(buffer);
664 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
666 if ((file = fopen( buffer, "r" )))
668 TRACE("(%s): found it in %s\n",
670 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
675 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
676 full_name.long_name );
677 if ((file = fopen( full_name.long_name, "r" )))
678 TRACE("(%s): found it in %s\n",
679 filename, full_name.long_name );
684 CurProfile->section = PROFILE_Load( file );
686 if(!stat(CurProfile->unix_name,&buf))
687 CurProfile->mtime=buf.st_mtime;
691 /* Does not exist yet, we will create it in PROFILE_FlushFile */
692 WARN("profile file %s not found\n", newdos_name );
698 /***********************************************************************
701 * Returns all keys of a section.
702 * If return_values is TRUE, also include the corresponding values.
704 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
705 LPSTR buffer, UINT len, BOOL handle_env,
710 if(!buffer) return 0;
714 if (section->name && !strcasecmp( section->name, section_name ))
717 for (key = section->key; key; key = key->next)
720 if (!*key->name) continue; /* Skip empty lines */
721 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
722 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
723 len -= strlen(buffer) + 1;
724 buffer += strlen(buffer) + 1;
725 if (return_values && key->value) {
727 PROFILE_CopyEntry ( buffer,
728 key->value, len - 1, handle_env );
729 len -= strlen(buffer) + 1;
730 buffer += strlen(buffer) + 1;
735 /*If either lpszSection or lpszKey is NULL and the supplied
736 destination buffer is too small to hold all the strings,
737 the last string is truncated and followed by two null characters.
738 In this case, the return value is equal to cchReturnBuffer
746 section = section->next;
748 buffer[0] = buffer[1] = '\0';
753 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
757 PROFILESECTION *section;
759 if(!buffer) return 0;
761 for (section = CurProfile->section; section; section = section->next)
763 l = strlen(section->name);
768 strcpy(buf, section->name);
778 /***********************************************************************
781 * Get a profile string.
783 * Tests with GetPrivateProfileString16, W95a,
784 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
785 * section key_name def_val res buffer
786 * "set1" "1" "x" 43 [data]
787 * "set1" "1 " "x" 43 [data] (!)
788 * "set1" " 1 "' "x" 43 [data] (!)
789 * "set1" "" "x" 1 "x"
790 * "set1" "" "x " 1 "x" (!)
791 * "set1" "" " x " 3 " x" (!)
792 * "set1" NULL "x" 6 "1\02\03\0\0"
793 * "set1" "" "x" 1 "x"
794 * NULL "1" "x" 0 "" (!)
800 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
801 LPCSTR def_val, LPSTR buffer, UINT len )
803 PROFILEKEY *key = NULL;
805 if(!buffer) return 0;
807 if (!def_val) def_val = "";
808 if (key_name && key_name[0])
810 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
811 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
813 TRACE("('%s','%s','%s'): returning '%s'\n",
814 section, key_name, def_val, buffer );
815 return strlen( buffer );
817 if (key_name && !(key_name[0]))
818 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
820 if (section && section[0])
821 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
828 /***********************************************************************
831 * Set a profile string.
833 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
836 if (!key_name) /* Delete a whole section */
838 TRACE("('%s')\n", section_name);
839 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
841 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
842 this is not an error on application's level.*/
844 else if (!value) /* Delete a key */
846 TRACE("('%s','%s')\n",
847 section_name, key_name );
848 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
849 section_name, key_name );
850 return TRUE; /* same error handling as above */
852 else /* Set the key value */
854 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
856 TRACE("('%s','%s','%s'): \n",
857 section_name, key_name, value );
858 if (!key) return FALSE;
861 /* strip the leading spaces. We can safely strip \n\r and
862 * friends too, they should not happen here anyway. */
863 while (PROFILE_isspace(*value)) value++;
865 if (!strcmp( key->value, value ))
867 TRACE(" no change needed\n" );
868 return TRUE; /* No change needed */
870 TRACE(" replacing '%s'\n", key->value );
871 HeapFree( GetProcessHeap(), 0, key->value );
873 else TRACE(" creating key\n" );
874 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
875 CurProfile->changed = TRUE;
881 /***********************************************************************
882 * PROFILE_GetWineIniString
884 * Get a config string from the wine.ini file.
886 int PROFILE_GetWineIniString( const char *section, const char *key_name,
887 const char *def, char *buffer, int len )
889 char tmp[PROFILE_MAX_LINE_LEN];
893 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
896 DWORD count = sizeof(tmp);
897 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
900 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
901 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
902 return strlen(buffer);
906 /***********************************************************************
907 * PROFILE_EnumWineIniString
909 * Get a config string from the wine.ini file.
911 BOOL PROFILE_EnumWineIniString( const char *section, int index,
912 char *name, int name_len, char *buffer, int len )
914 char tmp[PROFILE_MAX_LINE_LEN];
917 DWORD count = sizeof(tmp);
919 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
920 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
924 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
925 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
931 /***********************************************************************
932 * PROFILE_GetWineIniInt
934 * Get a config integer from the wine.ini file.
936 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
942 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
943 if (!buffer[0]) return def;
944 result = strtol( buffer, &p, 0 );
945 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
949 /******************************************************************************
951 * int PROFILE_GetWineIniBool(
952 * char const *section,
953 * char const *key_name,
956 * Reads a boolean value from the wine.ini file. This function attempts to
957 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
958 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
959 * true. Anything else results in the return of the default value.
961 * This function uses 1 to indicate true, and 0 for false. You can check
962 * for existence by setting def to something other than 0 or 1 and
963 * examining the return value.
965 int PROFILE_GetWineIniBool(
967 char const *key_name,
973 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
975 switch(key_value[0]) {
996 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name,
997 def ? "TRUE" : "FALSE", key_value[0],
998 retval ? "TRUE" : "FALSE");
1004 /***********************************************************************
1005 * PROFILE_LoadWineIni
1007 * Load the old .winerc file.
1009 int PROFILE_LoadWineIni(void)
1011 OBJECT_ATTRIBUTES attr;
1012 UNICODE_STRING nameW;
1013 char buffer[MAX_PATHNAME_LEN];
1019 attr.Length = sizeof(attr);
1020 attr.RootDirectory = 0;
1021 attr.ObjectName = &nameW;
1022 attr.Attributes = 0;
1023 attr.SecurityDescriptor = NULL;
1024 attr.SecurityQualityOfService = NULL;
1026 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1027 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1028 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1030 ERR("Cannot create config registry key\n" );
1033 RtlFreeUnicodeString( &nameW );
1036 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1037 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1038 NULL, REG_OPTION_VOLATILE, &disp ))
1040 ERR("Cannot create config registry key\n" );
1043 RtlFreeUnicodeString( &nameW );
1045 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1047 if ((p = getenv( "HOME" )) != NULL)
1049 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1050 strcat( buffer, PROFILE_WineIniName );
1051 if ((f = fopen( buffer, "r" )) != NULL)
1053 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1057 else WARN("could not get $HOME value for config file.\n" );
1059 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1061 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1066 if (disp == REG_OPENED_EXISTING_KEY)
1068 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1069 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1074 /* convert to the new format */
1075 sprintf( buffer, "%s/config", get_config_dir() );
1076 convert_config( f, buffer );
1079 MESSAGE( "The '%s' configuration file has been converted\n"
1080 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1081 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1082 "and then remove the old one and restart Wine.\n" );
1087 /***********************************************************************
1088 * PROFILE_UsageWineIni
1090 * Explain the wine.ini file to those who don't read documentation.
1091 * Keep below one screenful in length so that error messages above are
1094 void PROFILE_UsageWineIni(void)
1096 MESSAGE("Perhaps you have not properly edited or created "
1097 "your Wine configuration file.\n");
1098 MESSAGE("This is '%s/config'\n", get_config_dir());
1099 /* RTFM, so to say */
1102 /***********************************************************************
1103 * PROFILE_GetStringItem
1105 * Convenience function that turns a string 'xxx, yyy, zzz' into
1106 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1108 char* PROFILE_GetStringItem( char* start )
1112 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1116 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1118 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1120 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1123 if( lpch ) *lpch = '\0';
1127 /********************* API functions **********************************/
1129 /***********************************************************************
1130 * GetProfileInt16 (KERNEL.57)
1132 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1134 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1138 /***********************************************************************
1139 * GetProfileIntA (KERNEL32.264)
1141 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1143 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1146 /***********************************************************************
1147 * GetProfileIntW (KERNEL32.264)
1149 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1151 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1155 * undoc_feature means:
1156 * return section names string list if both section and entry are NULL.
1158 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1159 LPCSTR def_val, LPSTR buffer,
1160 UINT16 len, LPCSTR filename,
1161 BOOL undoc_feature )
1164 LPSTR pDefVal = NULL;
1167 filename = "win.ini";
1169 /* strip any trailing ' ' of def_val. */
1172 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1180 if (*p == ' ') /* ouch, contained trailing ' ' */
1182 int len = (int)p - (int)def_val;
1183 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1184 strncpy(pDefVal, def_val, len);
1185 pDefVal[len] = '\0';
1189 pDefVal = (LPSTR)def_val;
1191 EnterCriticalSection( &PROFILE_CritSect );
1193 if (PROFILE_Open( filename )) {
1194 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1195 /* undocumented; both section and entry are NULL */
1196 ret = PROFILE_GetSectionNames(buffer, len);
1198 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1200 lstrcpynA( buffer, pDefVal, len );
1201 ret = strlen( buffer );
1204 LeaveCriticalSection( &PROFILE_CritSect );
1206 if (pDefVal != def_val) /* allocated */
1207 HeapFree(GetProcessHeap(), 0, pDefVal);
1212 /***********************************************************************
1213 * GetPrivateProfileString16 (KERNEL.128)
1215 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1216 LPCSTR def_val, LPSTR buffer,
1217 UINT16 len, LPCSTR filename )
1219 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1220 buffer, len, filename, FALSE );
1223 /***********************************************************************
1224 * GetPrivateProfileStringA (KERNEL32.255)
1226 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1227 LPCSTR def_val, LPSTR buffer,
1228 UINT len, LPCSTR filename )
1230 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1231 buffer, len, filename, TRUE );
1234 /***********************************************************************
1235 * GetPrivateProfileStringW (KERNEL32.256)
1237 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1238 LPCWSTR def_val, LPWSTR buffer,
1239 UINT len, LPCWSTR filename )
1241 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1242 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1243 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1244 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1245 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1246 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1247 bufferA, len, filenameA );
1248 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1250 HeapFree( GetProcessHeap(), 0, sectionA );
1251 HeapFree( GetProcessHeap(), 0, entryA );
1252 HeapFree( GetProcessHeap(), 0, filenameA );
1253 HeapFree( GetProcessHeap(), 0, def_valA );
1254 HeapFree( GetProcessHeap(), 0, bufferA);
1258 /***********************************************************************
1259 * GetProfileString16 (KERNEL.58)
1261 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1262 LPSTR buffer, UINT16 len )
1264 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1265 buffer, len, "win.ini", FALSE );
1268 /***********************************************************************
1269 * GetProfileStringA (KERNEL32.268)
1271 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1272 LPSTR buffer, UINT len )
1274 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1275 buffer, len, "win.ini", TRUE );
1278 /***********************************************************************
1279 * GetProfileStringW (KERNEL32.269)
1281 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1282 LPCWSTR def_val, LPWSTR buffer, UINT len )
1284 return GetPrivateProfileStringW( section, entry, def_val,
1285 buffer, len, wininiW );
1288 /***********************************************************************
1289 * WriteProfileString16 (KERNEL.59)
1291 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1294 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1297 /***********************************************************************
1298 * WriteProfileStringA (KERNEL32.587)
1300 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1303 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1306 /***********************************************************************
1307 * WriteProfileStringW (KERNEL32.588)
1309 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1312 return WritePrivateProfileStringW( section, entry, string, wininiW );
1316 /***********************************************************************
1317 * GetPrivateProfileInt16 (KERNEL.127)
1319 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1320 INT16 def_val, LPCSTR filename )
1322 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1324 if (result > 65535) return 65535;
1325 if (result >= 0) return (UINT16)result;
1326 if (result < -32768) return -32768;
1327 return (UINT16)(INT16)result;
1330 /***********************************************************************
1331 * GetPrivateProfileIntA (KERNEL32.251)
1333 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1334 INT def_val, LPCSTR filename )
1340 PROFILE_GetPrivateProfileString( section, entry, "",
1341 buffer, sizeof(buffer), filename, FALSE );
1342 if (!buffer[0]) return (UINT)def_val;
1343 result = strtol( buffer, &p, 0 );
1344 if (p == buffer) return 0; /* No digits at all */
1345 return (UINT)result;
1348 /***********************************************************************
1349 * GetPrivateProfileIntW (KERNEL32.252)
1351 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1352 INT def_val, LPCWSTR filename )
1354 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1355 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1356 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1357 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1358 HeapFree( GetProcessHeap(), 0, sectionA );
1359 HeapFree( GetProcessHeap(), 0, filenameA );
1360 HeapFree( GetProcessHeap(), 0, entryA );
1364 /***********************************************************************
1365 * GetPrivateProfileSection16 (KERNEL.418)
1367 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1368 UINT16 len, LPCSTR filename )
1370 return GetPrivateProfileSectionA( section, buffer, len, filename );
1373 /***********************************************************************
1374 * GetPrivateProfileSectionA (KERNEL32.255)
1376 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1377 DWORD len, LPCSTR filename )
1381 EnterCriticalSection( &PROFILE_CritSect );
1383 if (PROFILE_Open( filename ))
1384 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1387 LeaveCriticalSection( &PROFILE_CritSect );
1392 /***********************************************************************
1393 * GetPrivateProfileSectionW (KERNEL32.256)
1396 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1397 DWORD len, LPCWSTR filename )
1400 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1401 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1402 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1403 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1405 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1406 HeapFree( GetProcessHeap(), 0, sectionA );
1407 HeapFree( GetProcessHeap(), 0, filenameA );
1408 HeapFree( GetProcessHeap(), 0, bufferA);
1412 /***********************************************************************
1413 * GetProfileSection16 (KERNEL.419)
1415 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1417 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1420 /***********************************************************************
1421 * GetProfileSectionA (KERNEL32.268)
1423 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1425 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1428 /***********************************************************************
1429 * GetProfileSectionW (KERNEL32)
1431 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1433 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1437 /***********************************************************************
1438 * WritePrivateProfileString16 (KERNEL.129)
1440 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1441 LPCSTR string, LPCSTR filename )
1443 return WritePrivateProfileStringA(section,entry,string,filename);
1446 /***********************************************************************
1447 * WritePrivateProfileStringA (KERNEL32.582)
1449 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1450 LPCSTR string, LPCSTR filename )
1454 EnterCriticalSection( &PROFILE_CritSect );
1456 if (PROFILE_Open( filename ))
1458 if (!section && !entry && !string)
1459 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1461 ret = PROFILE_SetString( section, entry, string );
1464 LeaveCriticalSection( &PROFILE_CritSect );
1468 /***********************************************************************
1469 * WritePrivateProfileStringW (KERNEL32.583)
1471 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1472 LPCWSTR string, LPCWSTR filename )
1474 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1475 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1476 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1477 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1478 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1479 stringA, filenameA );
1480 HeapFree( GetProcessHeap(), 0, sectionA );
1481 HeapFree( GetProcessHeap(), 0, entryA );
1482 HeapFree( GetProcessHeap(), 0, stringA );
1483 HeapFree( GetProcessHeap(), 0, filenameA );
1487 /***********************************************************************
1488 * WritePrivateProfileSection16 (KERNEL.416)
1490 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1491 LPCSTR string, LPCSTR filename )
1493 return WritePrivateProfileSectionA( section, string, filename );
1496 /***********************************************************************
1497 * WritePrivateProfileSectionA (KERNEL32)
1499 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1500 LPCSTR string, LPCSTR filename )
1505 EnterCriticalSection( &PROFILE_CritSect );
1507 if (PROFILE_Open( filename )) {
1508 if (!section && !string)
1509 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1510 else if (!string) /* delete the named section*/
1511 ret = PROFILE_SetString(section,NULL,NULL);
1513 PROFILE_DeleteAllKeys(section);
1516 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1517 if((p=strchr( buf, '='))){
1519 ret = PROFILE_SetString( section, buf, p+1 );
1522 HeapFree( GetProcessHeap(), 0, buf );
1523 string += strlen(string)+1;
1529 LeaveCriticalSection( &PROFILE_CritSect );
1533 /***********************************************************************
1534 * WritePrivateProfileSectionW (KERNEL32)
1536 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1537 LPCWSTR string, LPCWSTR filename)
1540 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1541 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1542 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1543 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1544 HeapFree( GetProcessHeap(), 0, sectionA );
1545 HeapFree( GetProcessHeap(), 0, stringA );
1546 HeapFree( GetProcessHeap(), 0, filenameA );
1550 /***********************************************************************
1551 * WriteProfileSection16 (KERNEL.417)
1553 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1555 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1558 /***********************************************************************
1559 * WriteProfileSectionA (KERNEL32.747)
1561 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1564 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1567 /***********************************************************************
1568 * WriteProfileSectionW (KERNEL32.748)
1570 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1572 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1575 /***********************************************************************
1576 * GetPrivateProfileSectionNames16 (KERNEL.143)
1578 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1583 EnterCriticalSection( &PROFILE_CritSect );
1585 if (PROFILE_Open( filename ))
1586 ret = PROFILE_GetSectionNames(buffer, size);
1588 LeaveCriticalSection( &PROFILE_CritSect );
1594 /***********************************************************************
1595 * GetProfileSectionNames16 (KERNEL.142)
1597 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1600 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1604 /***********************************************************************
1605 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1607 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1611 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1615 /***********************************************************************
1616 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1618 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1622 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1623 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1625 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1626 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1628 HeapFree( GetProcessHeap(), 0, bufferA);
1629 HeapFree( GetProcessHeap(), 0, filenameA );
1634 /***********************************************************************
1635 * GetPrivateProfileStruct16 (KERNEL.407)
1637 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1638 LPVOID buf, UINT16 len, LPCSTR filename)
1640 return GetPrivateProfileStructA( section, key, buf, len, filename );
1643 /***********************************************************************
1644 * GetPrivateProfileStructA (KERNEL32.370)
1646 * Should match Win95's behaviour pretty much
1648 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1649 LPVOID buf, UINT len, LPCSTR filename)
1653 EnterCriticalSection( &PROFILE_CritSect );
1655 if (PROFILE_Open( filename )) {
1656 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1658 TRACE("value (at %p): '%s'\n", k->value, k->value);
1659 if (((strlen(k->value) - 2) / 2) == len)
1666 end = k->value + strlen(k->value); /* -> '\0' */
1667 /* check for invalid chars in ASCII coded hex string */
1668 for (p=k->value; p < end; p++)
1672 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1673 *p, filename, section, key);
1680 BOOL highnibble = TRUE;
1682 LPBYTE binbuf = (LPBYTE)buf;
1684 end -= 2; /* don't include checksum in output data */
1685 /* translate ASCII hex format into binary data */
1686 for (p=k->value; p < end; p++)
1690 (c - 'A' + 10) : (c - '0');
1697 *binbuf++ = b; /* feed binary data into output */
1698 chksum += b; /* calculate checksum */
1700 highnibble ^= 1; /* toggle */
1702 /* retrieve stored checksum value */
1704 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1706 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1707 if (b == (chksum & 0xff)) /* checksums match ? */
1713 LeaveCriticalSection( &PROFILE_CritSect );
1718 /***********************************************************************
1719 * GetPrivateProfileStructW (KERNEL32.543)
1721 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1722 LPVOID buffer, UINT len, LPCWSTR filename)
1724 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1725 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1726 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1727 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1729 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1731 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1732 ((LPWSTR)buffer)[len-1] = 0;
1733 HeapFree( GetProcessHeap(), 0, bufferA);
1734 HeapFree( GetProcessHeap(), 0, sectionA );
1735 HeapFree( GetProcessHeap(), 0, keyA );
1736 HeapFree( GetProcessHeap(), 0, filenameA );
1743 /***********************************************************************
1744 * WritePrivateProfileStruct16 (KERNEL.406)
1746 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1747 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1749 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1752 /***********************************************************************
1753 * WritePrivateProfileStructA (KERNEL32.744)
1755 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1756 LPVOID buf, UINT bufsize, LPCSTR filename)
1763 if (!section && !key && !buf) /* flush the cache */
1764 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1766 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1767 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1769 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1770 *p++ = hex[*binbuf >> 4];
1771 *p++ = hex[*binbuf & 0xf];
1774 /* checksum is sum & 0xff */
1775 *p++ = hex[(sum & 0xf0) >> 4];
1776 *p++ = hex[sum & 0xf];
1779 EnterCriticalSection( &PROFILE_CritSect );
1781 if (PROFILE_Open( filename ))
1782 ret = PROFILE_SetString( section, key, outstring );
1784 LeaveCriticalSection( &PROFILE_CritSect );
1786 HeapFree( GetProcessHeap(), 0, outstring );
1791 /***********************************************************************
1792 * WritePrivateProfileStructW (KERNEL32.544)
1794 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1795 LPVOID buf, UINT bufsize, LPCWSTR filename)
1797 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1798 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1799 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1800 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1802 HeapFree( GetProcessHeap(), 0, sectionA );
1803 HeapFree( GetProcessHeap(), 0, keyA );
1804 HeapFree( GetProcessHeap(), 0, filenameA );
1810 /***********************************************************************
1811 * WriteOutProfiles (KERNEL.315)
1813 void WINAPI WriteOutProfiles16(void)
1815 EnterCriticalSection( &PROFILE_CritSect );
1816 PROFILE_FlushFile();
1817 LeaveCriticalSection( &PROFILE_CritSect );
1820 /***********************************************************************
1821 * CloseProfileUserMapping (KERNEL.138)
1823 BOOL WINAPI CloseProfileUserMapping(void) {
1824 FIXME("(), stub!\n");
1825 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);