4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
32 #include <sys/types.h>
42 #include "wine/winbase16.h"
46 #include "wine/unicode.h"
47 #include "wine/server.h"
48 #include "wine/library.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(profile);
53 typedef struct tagPROFILEKEY
56 struct tagPROFILEKEY *next;
60 typedef struct tagPROFILESECTION
62 struct tagPROFILEKEY *key;
63 struct tagPROFILESECTION *next;
71 PROFILESECTION *section;
79 #define N_CACHED_PROFILES 10
81 /* Cached profile files */
82 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
84 #define CurProfile (MRUProfile[0])
86 /* wine.ini config file registry root */
87 static HKEY wine_profile_key;
89 #define PROFILE_MAX_LINE_LEN 1024
91 /* Wine profile name in $HOME directory; must begin with slash */
92 static const char PROFILE_WineIniName[] = "/.winerc";
94 /* Wine profile: the profile file being used */
95 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
97 /* Check for comments in profile */
98 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
100 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
102 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
104 static const char hex[16] = "0123456789ABCDEF";
106 /***********************************************************************
109 * Copy the content of an entry into a buffer, removing quotes, and possibly
110 * translating environment variables.
112 static void PROFILE_CopyEntry( LPWSTR buffer, LPCWSTR value, int len,
113 int handle_env, BOOL strip_quote )
120 if (strip_quote && ((*value == '\'') || (*value == '\"')))
122 if (value[1] && (value[strlenW(value)-1] == *value)) quote = *value++;
127 lstrcpynW( buffer, value, len );
128 if (quote && (len >= strlenW(value))) buffer[strlenW(buffer)-1] = '\0';
132 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
134 if ((*p == '$') && (p[1] == '{'))
137 LPCWSTR p2 = strchrW( p, '}' );
139 if (!p2) continue; /* ignore it */
140 copy_len = min( 1024, (int)(p2-p)-1 );
141 strncpyW(env_val, p + 2, copy_len );
142 env_val[copy_len - 1] = 0; /* ensure 0 termination */
144 if (GetEnvironmentVariableW( env_val, buffer, len))
146 copy_len = strlenW( buffer );
153 if (quote && (len > 1)) buffer--;
158 /***********************************************************************
161 * Save a profile tree to a file.
163 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
166 char buffer[PROFILE_MAX_LINE_LEN];
168 for ( ; section; section = section->next)
170 if (section->name[0])
172 WideCharToMultiByte(CP_ACP, 0, section->name, -1, buffer, sizeof(buffer), NULL, NULL);
173 fprintf( file, "\r\n[%s]\r\n", buffer );
175 for (key = section->key; key; key = key->next)
177 WideCharToMultiByte(CP_ACP, 0, key->name, -1, buffer, sizeof(buffer), NULL, NULL);
178 fprintf( file, "%s", buffer );
181 WideCharToMultiByte(CP_ACP, 0, key->value, -1, buffer, sizeof(buffer), NULL, NULL);
182 fprintf( file, "=%s", buffer );
184 fprintf( file, "\r\n" );
190 /***********************************************************************
193 * Free a profile tree.
195 static void PROFILE_Free( PROFILESECTION *section )
197 PROFILESECTION *next_section;
198 PROFILEKEY *key, *next_key;
200 for ( ; section; section = next_section)
202 for (key = section->key; key; key = next_key)
204 next_key = key->next;
205 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
206 HeapFree( GetProcessHeap(), 0, key );
208 next_section = section->next;
209 HeapFree( GetProcessHeap(), 0, section );
213 static inline int PROFILE_isspace(char c)
215 if (isspace(c)) return 1;
216 if (c=='\r' || c==0x1a) return 1;
217 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
222 /***********************************************************************
225 * Load a profile tree from a file.
227 static PROFILESECTION *PROFILE_Load( FILE *file )
229 char buffer[PROFILE_MAX_LINE_LEN];
232 PROFILESECTION *section, *first_section;
233 PROFILESECTION **next_section;
234 PROFILEKEY *key, *prev_key, **next_key;
236 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
237 if(first_section == NULL) return NULL;
238 first_section->name[0] = 0;
239 first_section->key = NULL;
240 first_section->next = NULL;
241 next_section = &first_section->next;
242 next_key = &first_section->key;
245 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
249 while (*p && PROFILE_isspace(*p)) p++;
250 if (*p == '[') /* section start */
252 if (!(p2 = strrchr( p, ']' )))
254 WARN("Invalid section header at line %d: '%s'\n",
262 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) )))
264 MultiByteToWideChar(CP_ACP, 0, p, -1, section->name, len + 1);
266 section->next = NULL;
267 *next_section = section;
268 next_section = §ion->next;
269 next_key = §ion->key;
272 TRACE("New section: %s\n", debugstr_w(section->name));
279 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
281 if ((p2 = strchr( p, '=' )) != NULL)
284 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
286 while (*p2 && PROFILE_isspace(*p2)) p2++;
289 if(*p || !prev_key || *prev_key->name)
292 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + len * sizeof(WCHAR) ))) break;
293 MultiByteToWideChar(CP_ACP, 0, p, -1, key->name, len + 1);
296 len = strlen(p2) + 1;
297 key->value = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
298 MultiByteToWideChar(CP_ACP, 0, p2, -1, key->value, len);
300 else key->value = NULL;
304 next_key = &key->next;
307 TRACE("New key: name=%s, value=%s\n",
308 debugstr_w(key->name), key->value ? debugstr_w(key->value) : "(none)");
311 return first_section;
314 /* convert the .winerc file to the new format */
315 static void convert_config( FILE *in, const char *output_name )
317 char buffer[PROFILE_MAX_LINE_LEN];
321 /* create the output file, only if it doesn't exist already */
322 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
325 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
329 out = fdopen( fd, "w" );
330 fprintf( out, "WINE REGISTRY Version 2\n" );
331 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
332 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
334 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
336 while (*p && PROFILE_isspace(*p)) p++;
337 if (*p == '[') /* section start */
339 if ((p2 = strrchr( p, ']' )))
343 fprintf( out, "[%s]\n", p );
348 if (*p == ';' || *p == '#')
350 fprintf( out, "%s\n", p );
355 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
357 if ((p2 = strchr( p, '=' )) != NULL)
360 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
362 while (*p2 && PROFILE_isspace(*p2)) p2++;
367 fprintf( out, "\n" );
373 if (*p == '\\') fputc( '\\', out );
377 fprintf( out, "\" = \"" );
382 if (*p2 == '\\') fputc( '\\', out );
387 fprintf( out, "\"\n" );
393 /***********************************************************************
394 * PROFILE_DeleteSection
396 * Delete a section from a profile tree.
398 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCWSTR name )
402 if ((*section)->name[0] && !strcmpiW( (*section)->name, name ))
404 PROFILESECTION *to_del = *section;
405 *section = to_del->next;
407 PROFILE_Free( to_del );
410 section = &(*section)->next;
416 /***********************************************************************
419 * Delete a key from a profile tree.
421 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
422 LPCWSTR section_name, LPCWSTR key_name )
426 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
428 PROFILEKEY **key = &(*section)->key;
431 if (!strcmpiW( (*key)->name, key_name ))
433 PROFILEKEY *to_del = *key;
435 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
436 HeapFree( GetProcessHeap(), 0, to_del );
442 section = &(*section)->next;
448 /***********************************************************************
449 * PROFILE_DeleteAllKeys
451 * Delete all keys from a profile tree.
453 void PROFILE_DeleteAllKeys( LPCWSTR section_name)
455 PROFILESECTION **section= &CurProfile->section;
458 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
460 PROFILEKEY **key = &(*section)->key;
463 PROFILEKEY *to_del = *key;
465 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
466 HeapFree( GetProcessHeap(), 0, to_del );
467 CurProfile->changed =TRUE;
470 section = &(*section)->next;
475 /***********************************************************************
478 * Find a key in a profile tree, optionally creating it.
480 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, LPCWSTR section_name,
481 LPCWSTR key_name, BOOL create, BOOL create_always )
486 while (PROFILE_isspace(*section_name)) section_name++;
487 p = section_name + strlenW(section_name) - 1;
488 while ((p > section_name) && PROFILE_isspace(*p)) p--;
489 seclen = p - section_name + 1;
491 while (PROFILE_isspace(*key_name)) key_name++;
492 p = key_name + strlenW(key_name) - 1;
493 while ((p > key_name) && PROFILE_isspace(*p)) p--;
494 keylen = p - key_name + 1;
498 if ( ((*section)->name[0])
499 && (!(strncmpiW( (*section)->name, section_name, seclen )))
500 && (((*section)->name)[seclen] == '\0') )
502 PROFILEKEY **key = &(*section)->key;
506 /* If create_always is FALSE then we check if the keyname already exists.
507 * Otherwise we add it regardless of its existence, to allow
508 * keys to be added more then once in some cases.
512 if ( (!(strncmpiW( (*key)->name, key_name, keylen )))
513 && (((*key)->name)[keylen] == '\0') )
518 if (!create) return NULL;
519 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
521 strcpyW( (*key)->name, key_name );
522 (*key)->value = NULL;
526 section = &(*section)->next;
528 if (!create) return NULL;
529 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlenW(section_name) * sizeof(WCHAR) );
530 if(*section == NULL) return NULL;
531 strcpyW( (*section)->name, section_name );
532 (*section)->next = NULL;
533 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
534 sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
536 HeapFree(GetProcessHeap(), 0, *section);
539 strcpyW( (*section)->key->name, key_name );
540 (*section)->key->value = NULL;
541 (*section)->key->next = NULL;
542 return (*section)->key;
546 /***********************************************************************
549 * Flush the current profile to disk if changed.
551 static BOOL PROFILE_FlushFile(void)
553 char *p, buffer[MAX_PATHNAME_LEN];
554 const char *unix_name;
560 WARN("No current profile!\n");
564 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
565 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
567 int drive = toupperW(CurProfile->dos_name[0]) - 'A';
568 WCHAR *name, *name_lwr;
569 /* Try to create it in $HOME/.wine */
570 /* FIXME: this will need a more general solution */
571 strcpy( buffer, wine_get_config_dir() );
572 p = buffer + strlen(buffer);
574 *p = 0; /* make strlen() below happy */
575 name = strrchrW( CurProfile->dos_name, '\\' ) + 1;
577 /* create a lower cased version of the name */
578 name_lwr = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
579 strcpyW(name_lwr, name);
581 WideCharToMultiByte(DRIVE_GetCodepage(drive), 0, name_lwr, -1,
582 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
583 HeapFree(GetProcessHeap(), 0, name_lwr);
585 file = fopen( buffer, "w" );
591 WARN("could not save profile file %s\n", debugstr_w(CurProfile->dos_name));
595 TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile->dos_name), unix_name );
596 PROFILE_Save( file, CurProfile->section );
598 CurProfile->changed = FALSE;
599 if(!stat(unix_name,&buf))
600 CurProfile->mtime=buf.st_mtime;
605 /***********************************************************************
606 * PROFILE_ReleaseFile
608 * Flush the current profile to disk and remove it from the cache.
610 static void PROFILE_ReleaseFile(void)
613 PROFILE_Free( CurProfile->section );
614 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
615 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
616 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
617 CurProfile->changed = FALSE;
618 CurProfile->section = NULL;
619 CurProfile->dos_name = NULL;
620 CurProfile->unix_name = NULL;
621 CurProfile->filename = NULL;
622 CurProfile->mtime = 0;
626 /***********************************************************************
629 * Open a profile file, checking the cached file first.
631 static BOOL PROFILE_Open( LPCWSTR filename )
633 DOS_FULL_NAME full_name;
634 char buffer[MAX_PATHNAME_LEN];
636 WCHAR *name, *name_lwr;
641 PROFILE *tempProfile;
643 /* First time around */
646 for(i=0;i<N_CACHED_PROFILES;i++)
648 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
649 if(MRUProfile[i] == NULL) break;
650 MRUProfile[i]->changed=FALSE;
651 MRUProfile[i]->section=NULL;
652 MRUProfile[i]->dos_name=NULL;
653 MRUProfile[i]->unix_name=NULL;
654 MRUProfile[i]->filename=NULL;
655 MRUProfile[i]->mtime=0;
658 /* Check for a match */
660 if (strchrW( filename, '/' ) || strchrW( filename, '\\' ) ||
661 strchrW( filename, ':' ))
663 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
667 static const WCHAR bkslashW[] = {'\\',0};
668 WCHAR windirW[MAX_PATH];
670 GetWindowsDirectoryW( windirW, MAX_PATH );
671 strcatW( windirW, bkslashW );
672 strcatW( windirW, filename );
673 if (!DOSFS_GetFullName( windirW, FALSE, &full_name )) return FALSE;
676 for(i=0;i<N_CACHED_PROFILES;i++)
678 if ((MRUProfile[i]->filename && !strcmpW( filename, MRUProfile[i]->filename )) ||
679 (MRUProfile[i]->dos_name && !strcmpW( full_name.short_name, MRUProfile[i]->dos_name )))
684 tempProfile=MRUProfile[i];
686 MRUProfile[j]=MRUProfile[j-1];
687 CurProfile=tempProfile;
689 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
690 TRACE("(%s): already opened (mru=%d)\n",
691 debugstr_w(filename), i );
693 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
694 debugstr_w(filename), i );
699 /* Flush the old current profile */
702 /* Make the oldest profile the current one only in order to get rid of it */
703 if(i==N_CACHED_PROFILES)
705 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
706 for(i=N_CACHED_PROFILES-1;i>0;i--)
707 MRUProfile[i]=MRUProfile[i-1];
708 CurProfile=tempProfile;
710 if(CurProfile->filename) PROFILE_ReleaseFile();
712 /* OK, now that CurProfile is definitely free we assign it our new file */
713 newdos_name = HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name.short_name)+1) * sizeof(WCHAR) );
714 strcpyW( newdos_name, full_name.short_name );
715 CurProfile->dos_name = newdos_name;
716 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, (strlenW(filename)+1) * sizeof(WCHAR) );
717 strcpyW( CurProfile->filename, filename );
719 /* Try to open the profile file, first in $HOME/.wine */
721 /* FIXME: this will need a more general solution */
722 strcpy( buffer, wine_get_config_dir() );
723 p = buffer + strlen(buffer);
725 *p = 0; /* make strlen() below happy */
726 name = strrchrW( newdos_name, '\\' ) + 1;
728 /* create a lower cased version of the name */
729 name_lwr = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
730 strcpyW(name_lwr, name);
732 WideCharToMultiByte(DRIVE_GetCodepage(full_name.drive), 0, name_lwr, -1,
733 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
734 HeapFree(GetProcessHeap(), 0, name_lwr);
736 if ((file = fopen( buffer, "r" )))
738 TRACE("(%s): found it in %s\n", debugstr_w(filename), buffer );
739 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
740 strcpy( CurProfile->unix_name, buffer );
744 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
745 strcpy( CurProfile->unix_name, full_name.long_name );
746 if ((file = fopen( full_name.long_name, "r" )))
747 TRACE("(%s): found it in %s\n",
748 debugstr_w(filename), full_name.long_name );
753 CurProfile->section = PROFILE_Load( file );
755 if(!stat(CurProfile->unix_name,&buf))
756 CurProfile->mtime=buf.st_mtime;
760 /* Does not exist yet, we will create it in PROFILE_FlushFile */
761 WARN("profile file %s not found\n", debugstr_w(newdos_name) );
767 /***********************************************************************
770 * Returns all keys of a section.
771 * If return_values is TRUE, also include the corresponding values.
773 static INT PROFILE_GetSection( PROFILESECTION *section, LPCWSTR section_name,
774 LPWSTR buffer, UINT len, BOOL handle_env,
779 if(!buffer) return 0;
781 TRACE("%s,%p,%u\n", debugstr_w(section_name), buffer, len);
785 if (section->name[0] && !strcmpiW( section->name, section_name ))
788 for (key = section->key; key; key = key->next)
791 if (!*key->name) continue; /* Skip empty lines */
792 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
793 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env, 0 );
794 len -= strlenW(buffer) + 1;
795 buffer += strlenW(buffer) + 1;
798 if (return_values && key->value) {
800 PROFILE_CopyEntry ( buffer,
801 key->value, len - 1, handle_env, 0 );
802 len -= strlenW(buffer) + 1;
803 buffer += strlenW(buffer) + 1;
808 /*If either lpszSection or lpszKey is NULL and the supplied
809 destination buffer is too small to hold all the strings,
810 the last string is truncated and followed by two null characters.
811 In this case, the return value is equal to cchReturnBuffer
819 section = section->next;
821 buffer[0] = buffer[1] = '\0';
825 /* See GetPrivateProfileSectionNamesA for documentation */
826 static INT PROFILE_GetSectionNames( LPWSTR buffer, UINT len )
830 PROFILESECTION *section;
841 section = CurProfile->section;
842 while ((section!=NULL)) {
843 if (section->name[0]) {
844 l = strlenW(section->name)+1;
847 strncpyW(buf, section->name, f-1);
854 strcpyW(buf, section->name);
858 section = section->next;
865 /***********************************************************************
868 * Get a profile string.
870 * Tests with GetPrivateProfileString16, W95a,
871 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
872 * section key_name def_val res buffer
873 * "set1" "1" "x" 43 [data]
874 * "set1" "1 " "x" 43 [data] (!)
875 * "set1" " 1 "' "x" 43 [data] (!)
876 * "set1" "" "x" 1 "x"
877 * "set1" "" "x " 1 "x" (!)
878 * "set1" "" " x " 3 " x" (!)
879 * "set1" NULL "x" 6 "1\02\03\0\0"
880 * "set1" "" "x" 1 "x"
881 * NULL "1" "x" 0 "" (!)
887 static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name,
888 LPCWSTR def_val, LPWSTR buffer, UINT len )
890 PROFILEKEY *key = NULL;
891 static const WCHAR empty_strW[] = { 0 };
893 if(!buffer) return 0;
895 if (!def_val) def_val = empty_strW;
900 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
903 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
904 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
906 TRACE("(%s,%s,%s): returning %s\n",
907 debugstr_w(section), debugstr_w(key_name),
908 debugstr_w(def_val), debugstr_w(buffer) );
909 return strlenW( buffer );
911 /* no "else" here ! */
912 if (section && section[0])
914 INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE, FALSE);
915 if (!buffer[0]) /* no luck -> def_val */
917 PROFILE_CopyEntry(buffer, def_val, len, FALSE, TRUE);
918 ret = strlenW(buffer);
927 /***********************************************************************
930 * Set a profile string.
932 static BOOL PROFILE_SetString( LPCWSTR section_name, LPCWSTR key_name,
933 LPCWSTR value, BOOL create_always )
935 if (!key_name) /* Delete a whole section */
937 TRACE("(%s)\n", debugstr_w(section_name));
938 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
940 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
941 this is not an error on application's level.*/
943 else if (!value) /* Delete a key */
945 TRACE("(%s,%s)\n", debugstr_w(section_name), debugstr_w(key_name) );
946 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
947 section_name, key_name );
948 return TRUE; /* same error handling as above */
950 else /* Set the key value */
952 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
953 key_name, TRUE, create_always );
954 TRACE("(%s,%s,%s):\n",
955 debugstr_w(section_name), debugstr_w(key_name), debugstr_w(value) );
956 if (!key) return FALSE;
959 /* strip the leading spaces. We can safely strip \n\r and
960 * friends too, they should not happen here anyway. */
961 while (PROFILE_isspace(*value)) value++;
963 if (!strcmpW( key->value, value ))
965 TRACE(" no change needed\n" );
966 return TRUE; /* No change needed */
968 TRACE(" replacing %s\n", debugstr_w(key->value) );
969 HeapFree( GetProcessHeap(), 0, key->value );
971 else TRACE(" creating key\n" );
972 key->value = HeapAlloc( GetProcessHeap(), 0, (strlenW(value)+1) * sizeof(WCHAR) );
973 strcpyW( key->value, value );
974 CurProfile->changed = TRUE;
980 /***********************************************************************
981 * PROFILE_GetWineIniString
983 * Get a config string from the wine.ini file.
985 int PROFILE_GetWineIniString( LPCWSTR section, LPCWSTR key_name,
986 LPCWSTR def, LPWSTR buffer, int len )
990 OBJECT_ATTRIBUTES attr;
991 UNICODE_STRING nameW;
993 attr.Length = sizeof(attr);
994 attr.RootDirectory = wine_profile_key;
995 attr.ObjectName = &nameW;
997 attr.SecurityDescriptor = NULL;
998 attr.SecurityQualityOfService = NULL;
999 RtlInitUnicodeString( &nameW, section );
1000 if (!(err = NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )))
1002 char tmp[PROFILE_MAX_LINE_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1005 RtlInitUnicodeString( &nameW, key_name );
1006 if (!(err = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1007 tmp, sizeof(tmp), &count )))
1009 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1010 PROFILE_CopyEntry( buffer, str, len, TRUE, TRUE );
1015 if (err) PROFILE_CopyEntry( buffer, def, len, TRUE, TRUE );
1016 TRACE( "(%s,%s,%s): returning %s\n", debugstr_w(section),
1017 debugstr_w(key_name), debugstr_w(def), debugstr_w(buffer) );
1018 return strlenW(buffer);
1022 /******************************************************************************
1024 * PROFILE_GetWineIniBool
1026 * Reads a boolean value from the wine.ini file. This function attempts to
1027 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
1028 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
1029 * true. Anything else results in the return of the default value.
1031 * This function uses 1 to indicate true, and 0 for false. You can check
1032 * for existence by setting def to something other than 0 or 1 and
1033 * examining the return value.
1035 int PROFILE_GetWineIniBool( LPCWSTR section, LPCWSTR key_name, int def )
1037 static const WCHAR def_valueW[] = {'~',0};
1041 PROFILE_GetWineIniString(section, key_name, def_valueW, key_value, 2);
1043 switch(key_value[0]) {
1064 TRACE("(%s, %s, %s), [%c], ret %s\n", debugstr_w(section), debugstr_w(key_name),
1065 def ? "TRUE" : "FALSE", key_value[0],
1066 retval ? "TRUE" : "FALSE");
1072 /***********************************************************************
1073 * PROFILE_LoadWineIni
1075 * Load the old .winerc file.
1077 int PROFILE_LoadWineIni(void)
1079 OBJECT_ATTRIBUTES attr;
1080 UNICODE_STRING nameW;
1081 char buffer[MAX_PATHNAME_LEN];
1087 attr.Length = sizeof(attr);
1088 attr.RootDirectory = 0;
1089 attr.ObjectName = &nameW;
1090 attr.Attributes = 0;
1091 attr.SecurityDescriptor = NULL;
1092 attr.SecurityQualityOfService = NULL;
1094 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1095 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1096 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1098 ERR("Cannot create config registry key\n" );
1101 RtlFreeUnicodeString( &nameW );
1104 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1105 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1106 NULL, REG_OPTION_VOLATILE, &disp ))
1108 ERR("Cannot create config registry key\n" );
1111 RtlFreeUnicodeString( &nameW );
1113 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1115 if ((p = getenv( "HOME" )) != NULL)
1117 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1118 strcat( buffer, PROFILE_WineIniName );
1119 if ((f = fopen( buffer, "r" )) != NULL)
1121 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1123 /* convert to the new format */
1124 sprintf( buffer, "%s/config", wine_get_config_dir() );
1125 convert_config( f, buffer );
1128 MESSAGE( "The '%s' configuration file has been converted\n"
1129 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1130 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1131 "and then remove the old one and restart Wine.\n" );
1135 else WARN("could not get $HOME value for config file.\n" );
1137 MESSAGE( "Can't open configuration file %s/config\n", wine_get_config_dir() );
1142 /***********************************************************************
1143 * PROFILE_UsageWineIni
1145 * Explain the wine.ini file to those who don't read documentation.
1146 * Keep below one screenful in length so that error messages above are
1149 void PROFILE_UsageWineIni(void)
1151 MESSAGE("Perhaps you have not properly edited or created "
1152 "your Wine configuration file.\n");
1153 MESSAGE("This is (supposed to be) '%s/config'\n", wine_get_config_dir());
1154 /* RTFM, so to say */
1158 /********************* API functions **********************************/
1160 /***********************************************************************
1161 * GetProfileInt (KERNEL.57)
1163 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1165 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1169 /***********************************************************************
1170 * GetProfileIntA (KERNEL32.@)
1172 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1174 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1177 /***********************************************************************
1178 * GetProfileIntW (KERNEL32.@)
1180 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1182 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1186 * if allow_section_name_copy is TRUE, allow the copying :
1187 * - of Section names if 'section' is NULL
1188 * - of Keys in a Section if 'entry' is NULL
1189 * (see MSDN doc for GetPrivateProfileString)
1191 static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry,
1192 LPCWSTR def_val, LPWSTR buffer,
1193 UINT len, LPCWSTR filename,
1194 BOOL allow_section_name_copy )
1197 LPWSTR pDefVal = NULL;
1202 TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section), debugstr_w(entry),
1203 debugstr_w(def_val), buffer, len, debugstr_w(filename));
1205 /* strip any trailing ' ' of def_val. */
1208 LPCWSTR p = &def_val[strlenW(def_val)]; /* even "" works ! */
1216 if (*p == ' ') /* ouch, contained trailing ' ' */
1218 int len = (int)(p - def_val);
1219 pDefVal = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1220 strncpyW(pDefVal, def_val, len);
1221 pDefVal[len] = '\0';
1225 pDefVal = (LPWSTR)def_val;
1227 EnterCriticalSection( &PROFILE_CritSect );
1229 if (PROFILE_Open( filename )) {
1230 if ((allow_section_name_copy) && (section == NULL))
1231 ret = PROFILE_GetSectionNames(buffer, len);
1233 /* PROFILE_GetString already handles the 'entry == NULL' case */
1234 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1236 lstrcpynW( buffer, pDefVal, len );
1237 ret = strlenW( buffer );
1240 LeaveCriticalSection( &PROFILE_CritSect );
1242 if (pDefVal != def_val) /* allocated */
1243 HeapFree(GetProcessHeap(), 0, pDefVal);
1245 TRACE("returning %s, %d\n", debugstr_w(buffer), ret);
1250 /***********************************************************************
1251 * GetPrivateProfileString (KERNEL.128)
1253 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1254 LPCSTR def_val, LPSTR buffer,
1255 UINT16 len, LPCSTR filename )
1257 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1259 INT16 retW, ret = 0;
1261 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1262 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1263 else sectionW.Buffer = NULL;
1264 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1265 else entryW.Buffer = NULL;
1266 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1267 else def_valW.Buffer = NULL;
1268 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1269 else filenameW.Buffer = NULL;
1271 retW = PROFILE_GetPrivateProfileString( sectionW.Buffer, entryW.Buffer,
1272 def_valW.Buffer, bufferW, len,
1273 filenameW.Buffer, FALSE );
1276 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1283 ret--; /* strip terminating 0 */
1286 RtlFreeUnicodeString(§ionW);
1287 RtlFreeUnicodeString(&entryW);
1288 RtlFreeUnicodeString(&def_valW);
1289 RtlFreeUnicodeString(&filenameW);
1290 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1294 /***********************************************************************
1295 * GetPrivateProfileStringA (KERNEL32.@)
1297 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1298 LPCSTR def_val, LPSTR buffer,
1299 UINT len, LPCSTR filename )
1301 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1305 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1306 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1307 else sectionW.Buffer = NULL;
1308 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1309 else entryW.Buffer = NULL;
1310 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1311 else def_valW.Buffer = NULL;
1312 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1313 else filenameW.Buffer = NULL;
1315 retW = GetPrivateProfileStringW( sectionW.Buffer, entryW.Buffer,
1316 def_valW.Buffer, bufferW, len,
1320 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1327 ret--; /* strip terminating 0 */
1330 RtlFreeUnicodeString(§ionW);
1331 RtlFreeUnicodeString(&entryW);
1332 RtlFreeUnicodeString(&def_valW);
1333 RtlFreeUnicodeString(&filenameW);
1334 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1338 /***********************************************************************
1339 * GetPrivateProfileStringW (KERNEL32.@)
1341 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1342 LPCWSTR def_val, LPWSTR buffer,
1343 UINT len, LPCWSTR filename )
1345 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1346 buffer, len, filename, TRUE );
1349 /***********************************************************************
1350 * GetProfileString (KERNEL.58)
1352 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1353 LPSTR buffer, UINT16 len )
1355 return GetPrivateProfileString16( section, entry, def_val,
1356 buffer, len, "win.ini" );
1359 /***********************************************************************
1360 * GetProfileStringA (KERNEL32.@)
1362 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1363 LPSTR buffer, UINT len )
1365 return GetPrivateProfileStringA( section, entry, def_val,
1366 buffer, len, "win.ini" );
1369 /***********************************************************************
1370 * GetProfileStringW (KERNEL32.@)
1372 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1373 LPCWSTR def_val, LPWSTR buffer, UINT len )
1375 return GetPrivateProfileStringW( section, entry, def_val,
1376 buffer, len, wininiW );
1379 /***********************************************************************
1380 * WriteProfileString (KERNEL.59)
1382 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1385 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1388 /***********************************************************************
1389 * WriteProfileStringA (KERNEL32.@)
1391 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1394 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1397 /***********************************************************************
1398 * WriteProfileStringW (KERNEL32.@)
1400 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1403 return WritePrivateProfileStringW( section, entry, string, wininiW );
1407 /***********************************************************************
1408 * GetPrivateProfileInt (KERNEL.127)
1410 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1411 INT16 def_val, LPCSTR filename )
1413 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1414 * here, but Win98SE doesn't care about this at all, so I deleted it.
1415 * AFAIR versions prior to Win9x had these limits, though. */
1416 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
1419 /***********************************************************************
1420 * GetPrivateProfileIntA (KERNEL32.@)
1422 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1423 INT def_val, LPCSTR filename )
1428 if (!GetPrivateProfileStringA( section, entry, "",
1429 buffer, sizeof(buffer), filename ))
1431 /* FIXME: if entry can be found but it's empty, then Win16 is
1432 * supposed to return 0 instead of def_val ! Difficult/problematic
1433 * to implement (every other failure also returns zero buffer),
1434 * thus wait until testing framework avail for making sure nothing
1435 * else gets broken that way. */
1436 if (!buffer[0]) return (UINT)def_val;
1438 /* Don't use strtol() here !
1439 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1440 YES, scan for unsigned format ! (otherwise compatibility error) */
1441 if (!sscanf(buffer, "%lu", &result)) return 0;
1442 return (UINT)result;
1445 /***********************************************************************
1446 * GetPrivateProfileIntW (KERNEL32.@)
1448 * FIXME: rewrite using unicode
1450 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1451 INT def_val, LPCWSTR filename )
1453 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1454 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1455 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1456 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1457 HeapFree( GetProcessHeap(), 0, sectionA );
1458 HeapFree( GetProcessHeap(), 0, filenameA );
1459 HeapFree( GetProcessHeap(), 0, entryA );
1463 /***********************************************************************
1464 * GetPrivateProfileSection (KERNEL.418)
1466 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1467 UINT16 len, LPCSTR filename )
1469 return GetPrivateProfileSectionA( section, buffer, len, filename );
1472 /***********************************************************************
1473 * GetPrivateProfileSectionW (KERNEL32.@)
1475 INT WINAPI GetPrivateProfileSectionW( LPCWSTR section, LPWSTR buffer,
1476 DWORD len, LPCWSTR filename )
1480 EnterCriticalSection( &PROFILE_CritSect );
1482 if (PROFILE_Open( filename ))
1483 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1486 LeaveCriticalSection( &PROFILE_CritSect );
1491 /***********************************************************************
1492 * GetPrivateProfileSectionA (KERNEL32.@)
1494 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1495 DWORD len, LPCSTR filename )
1497 UNICODE_STRING sectionW, filenameW;
1501 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1502 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1503 else sectionW.Buffer = NULL;
1504 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1505 else filenameW.Buffer = NULL;
1507 retW = GetPrivateProfileSectionW(sectionW.Buffer, bufferW, len, filenameW.Buffer);
1510 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 2, buffer, len, NULL, NULL);
1526 RtlFreeUnicodeString(§ionW);
1527 RtlFreeUnicodeString(&filenameW);
1528 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1532 /***********************************************************************
1533 * GetProfileSection (KERNEL.419)
1535 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1537 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1540 /***********************************************************************
1541 * GetProfileSectionA (KERNEL32.@)
1543 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1545 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1548 /***********************************************************************
1549 * GetProfileSectionW (KERNEL32.@)
1551 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1553 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1557 /***********************************************************************
1558 * WritePrivateProfileString (KERNEL.129)
1560 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1561 LPCSTR string, LPCSTR filename )
1563 return WritePrivateProfileStringA(section,entry,string,filename);
1566 /***********************************************************************
1567 * WritePrivateProfileStringW (KERNEL32.@)
1569 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1570 LPCWSTR string, LPCWSTR filename )
1574 EnterCriticalSection( &PROFILE_CritSect );
1576 if (PROFILE_Open( filename ))
1578 if (!section && !entry && !string) /* documented "file flush" case */
1580 PROFILE_FlushFile();
1581 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1585 FIXME("(NULL?,%s,%s,%s)?\n",
1586 debugstr_w(entry), debugstr_w(string), debugstr_w(filename));
1588 ret = PROFILE_SetString( section, entry, string, FALSE);
1589 PROFILE_FlushFile();
1594 LeaveCriticalSection( &PROFILE_CritSect );
1598 /***********************************************************************
1599 * WritePrivateProfileStringA (KERNEL32.@)
1601 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1602 LPCSTR string, LPCSTR filename )
1604 UNICODE_STRING sectionW, entryW, stringW, filenameW;
1607 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1608 else sectionW.Buffer = NULL;
1609 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1610 else entryW.Buffer = NULL;
1611 if (string) RtlCreateUnicodeStringFromAsciiz(&stringW, string);
1612 else stringW.Buffer = NULL;
1613 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1614 else filenameW.Buffer = NULL;
1616 ret = WritePrivateProfileStringW(sectionW.Buffer, entryW.Buffer,
1617 stringW.Buffer, filenameW.Buffer);
1618 RtlFreeUnicodeString(§ionW);
1619 RtlFreeUnicodeString(&entryW);
1620 RtlFreeUnicodeString(&stringW);
1621 RtlFreeUnicodeString(&filenameW);
1625 /***********************************************************************
1626 * WritePrivateProfileSection (KERNEL.416)
1628 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1629 LPCSTR string, LPCSTR filename )
1631 return WritePrivateProfileSectionA( section, string, filename );
1634 /***********************************************************************
1635 * WritePrivateProfileSectionW (KERNEL32.@)
1637 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1638 LPCWSTR string, LPCWSTR filename )
1643 EnterCriticalSection( &PROFILE_CritSect );
1645 if (PROFILE_Open( filename )) {
1646 if (!section && !string)
1647 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1648 else if (!string) {/* delete the named section*/
1649 ret = PROFILE_SetString(section,NULL,NULL, FALSE);
1650 PROFILE_FlushFile();
1652 PROFILE_DeleteAllKeys(section);
1655 LPWSTR buf = HeapAlloc( GetProcessHeap(), 0, (strlenW(string)+1) * sizeof(WCHAR) );
1656 strcpyW( buf, string );
1657 if((p = strchrW( buf, '='))) {
1659 ret = PROFILE_SetString( section, buf, p+1, TRUE);
1661 HeapFree( GetProcessHeap(), 0, buf );
1662 string += strlenW(string)+1;
1664 PROFILE_FlushFile();
1668 LeaveCriticalSection( &PROFILE_CritSect );
1672 /***********************************************************************
1673 * WritePrivateProfileSectionA (KERNEL32.@)
1675 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1676 LPCSTR string, LPCSTR filename)
1679 UNICODE_STRING sectionW, filenameW;
1688 while(*p) p += strlen(p) + 1;
1689 lenA = p - string + 1;
1690 lenW = MultiByteToWideChar(CP_ACP, 0, string, lenA, NULL, 0);
1691 if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR))))
1692 MultiByteToWideChar(CP_ACP, 0, string, lenA, stringW, lenW);
1694 else stringW = NULL;
1695 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1696 else sectionW.Buffer = NULL;
1697 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1698 else filenameW.Buffer = NULL;
1700 ret = WritePrivateProfileSectionW(sectionW.Buffer, stringW, filenameW.Buffer);
1702 HeapFree(GetProcessHeap(), 0, stringW);
1703 RtlFreeUnicodeString(§ionW);
1704 RtlFreeUnicodeString(&filenameW);
1708 /***********************************************************************
1709 * WriteProfileSection (KERNEL.417)
1711 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1713 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1716 /***********************************************************************
1717 * WriteProfileSectionA (KERNEL32.@)
1719 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1722 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1725 /***********************************************************************
1726 * WriteProfileSectionW (KERNEL32.@)
1728 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1730 return WritePrivateProfileSectionW(section, keys_n_values, wininiW);
1733 /***********************************************************************
1734 * GetPrivateProfileSectionNames (KERNEL.143)
1736 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1739 return GetPrivateProfileSectionNamesA(buffer,size,filename);
1743 /***********************************************************************
1744 * GetProfileSectionNames (KERNEL.142)
1746 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
1749 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
1753 /***********************************************************************
1754 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1756 * Returns the section names contained in the specified file.
1757 * FIXME: Where do we find this file when the path is relative?
1758 * The section names are returned as a list of strings with an extra
1759 * '\0' to mark the end of the list. Except for that the behavior
1760 * depends on the Windows version.
1763 * - if the buffer is 0 or 1 character long then it is as if it was of
1765 * - otherwise, if the buffer is to small only the section names that fit
1767 * - note that this means if the buffer was to small to return even just
1768 * the first section name then a single '\0' will be returned.
1769 * - the return value is the number of characters written in the buffer,
1770 * except if the buffer was too smal in which case len-2 is returned
1773 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1774 * '\0' and the return value is 0
1775 * - otherwise if the buffer is too small then the first section name that
1776 * does not fit is truncated so that the string list can be terminated
1777 * correctly (double '\0')
1778 * - the return value is the number of characters written in the buffer
1779 * except for the trailing '\0'. If the buffer is too small, then the
1780 * return value is len-2
1781 * - Win2000 has a bug that triggers when the section names and the
1782 * trailing '\0' fit exactly in the buffer. In that case the trailing
1785 * Wine implements the observed Win2000 behavior (except for the bug).
1787 * Note that when the buffer is big enough then the return value may be any
1788 * value between 1 and len-1 (or len in Win95), including len-2.
1790 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1795 EnterCriticalSection( &PROFILE_CritSect );
1797 if (PROFILE_Open( filename ))
1798 ret = PROFILE_GetSectionNames(buffer, size);
1800 LeaveCriticalSection( &PROFILE_CritSect );
1806 /***********************************************************************
1807 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1809 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1812 UNICODE_STRING filenameW;
1816 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)) : NULL;
1817 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1818 else filenameW.Buffer = NULL;
1820 retW = GetPrivateProfileSectionNamesW(bufferW, size, filenameW.Buffer);
1823 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW, buffer, size, NULL, NULL);
1831 RtlFreeUnicodeString(&filenameW);
1832 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1836 /***********************************************************************
1837 * GetPrivateProfileStruct (KERNEL.407)
1839 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1840 LPVOID buf, UINT16 len, LPCSTR filename)
1842 return GetPrivateProfileStructA( section, key, buf, len, filename );
1845 /***********************************************************************
1846 * GetPrivateProfileStructW (KERNEL32.@)
1848 * Should match Win95's behaviour pretty much
1850 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1851 LPVOID buf, UINT len, LPCWSTR filename)
1855 EnterCriticalSection( &PROFILE_CritSect );
1857 if (PROFILE_Open( filename )) {
1858 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
1860 TRACE("value (at %p): %s\n", k->value, debugstr_w(k->value));
1861 if (((strlenW(k->value) - 2) / 2) == len)
1868 end = k->value + strlenW(k->value); /* -> '\0' */
1869 /* check for invalid chars in ASCII coded hex string */
1870 for (p=k->value; p < end; p++)
1874 WARN("invalid char '%x' in file %s->[%s]->%s !\n",
1875 *p, debugstr_w(filename), debugstr_w(section), debugstr_w(key));
1882 BOOL highnibble = TRUE;
1884 LPBYTE binbuf = (LPBYTE)buf;
1886 end -= 2; /* don't include checksum in output data */
1887 /* translate ASCII hex format into binary data */
1888 for (p=k->value; p < end; p++)
1892 (c - 'A' + 10) : (c - '0');
1899 *binbuf++ = b; /* feed binary data into output */
1900 chksum += b; /* calculate checksum */
1902 highnibble ^= 1; /* toggle */
1904 /* retrieve stored checksum value */
1906 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1908 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1909 if (b == (chksum & 0xff)) /* checksums match ? */
1915 LeaveCriticalSection( &PROFILE_CritSect );
1920 /***********************************************************************
1921 * GetPrivateProfileStructA (KERNEL32.@)
1923 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1924 LPVOID buffer, UINT len, LPCSTR filename)
1926 UNICODE_STRING sectionW, keyW, filenameW;
1929 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1930 else sectionW.Buffer = NULL;
1931 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
1932 else keyW.Buffer = NULL;
1933 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1934 else filenameW.Buffer = NULL;
1936 ret = GetPrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buffer, len,
1938 /* Do not translate binary data. */
1940 RtlFreeUnicodeString(§ionW);
1941 RtlFreeUnicodeString(&keyW);
1942 RtlFreeUnicodeString(&filenameW);
1948 /***********************************************************************
1949 * WritePrivateProfileStruct (KERNEL.406)
1951 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1952 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1954 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1957 /***********************************************************************
1958 * WritePrivateProfileStructW (KERNEL32.@)
1960 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1961 LPVOID buf, UINT bufsize, LPCWSTR filename)
1965 LPWSTR outstring, p;
1968 if (!section && !key && !buf) /* flush the cache */
1969 return WritePrivateProfileStringW( NULL, NULL, NULL, filename );
1971 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1972 outstring = HeapAlloc( GetProcessHeap(), 0, (bufsize*2 + 2 + 1) * sizeof(WCHAR) );
1974 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1975 *p++ = hex[*binbuf >> 4];
1976 *p++ = hex[*binbuf & 0xf];
1979 /* checksum is sum & 0xff */
1980 *p++ = hex[(sum & 0xf0) >> 4];
1981 *p++ = hex[sum & 0xf];
1984 EnterCriticalSection( &PROFILE_CritSect );
1986 if (PROFILE_Open( filename )) {
1987 ret = PROFILE_SetString( section, key, outstring, FALSE);
1988 PROFILE_FlushFile();
1991 LeaveCriticalSection( &PROFILE_CritSect );
1993 HeapFree( GetProcessHeap(), 0, outstring );
1998 /***********************************************************************
1999 * WritePrivateProfileStructA (KERNEL32.@)
2001 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
2002 LPVOID buf, UINT bufsize, LPCSTR filename)
2004 UNICODE_STRING sectionW, keyW, filenameW;
2007 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
2008 else sectionW.Buffer = NULL;
2009 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
2010 else keyW.Buffer = NULL;
2011 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
2012 else filenameW.Buffer = NULL;
2014 /* Do not translate binary data. */
2015 ret = WritePrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buf, bufsize,
2018 RtlFreeUnicodeString(§ionW);
2019 RtlFreeUnicodeString(&keyW);
2020 RtlFreeUnicodeString(&filenameW);
2025 /***********************************************************************
2026 * WriteOutProfiles (KERNEL.315)
2028 void WINAPI WriteOutProfiles16(void)
2030 EnterCriticalSection( &PROFILE_CritSect );
2031 PROFILE_FlushFile();
2032 LeaveCriticalSection( &PROFILE_CritSect );
2035 /***********************************************************************
2036 * CloseProfileUserMapping (KERNEL32.@)
2038 BOOL WINAPI CloseProfileUserMapping(void) {
2039 FIXME("(), stub!\n");
2040 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);