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';
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;
576 WideCharToMultiByte(DRIVE_GetCodepage(drive
), 0, name
, -1,
577 p
, sizeof(buffer
) - strlen(buffer
), NULL
, NULL
);
578 file
= fopen( buffer
, "w" );
584 WARN("could not save profile file %s\n", debugstr_w(CurProfile
->dos_name
));
588 TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile
->dos_name
), unix_name
);
589 PROFILE_Save( file
, CurProfile
->section
);
591 CurProfile
->changed
= FALSE
;
592 if(!stat(unix_name
,&buf
))
593 CurProfile
->mtime
=buf
.st_mtime
;
598 /***********************************************************************
599 * PROFILE_ReleaseFile
601 * Flush the current profile to disk and remove it from the cache.
603 static void PROFILE_ReleaseFile(void)
606 PROFILE_Free( CurProfile
->section
);
607 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
608 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
609 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
610 CurProfile
->changed
= FALSE
;
611 CurProfile
->section
= NULL
;
612 CurProfile
->dos_name
= NULL
;
613 CurProfile
->unix_name
= NULL
;
614 CurProfile
->filename
= NULL
;
615 CurProfile
->mtime
= 0;
619 /***********************************************************************
622 * Open a profile file, checking the cached file first.
624 static BOOL
PROFILE_Open( LPCWSTR filename
)
626 DOS_FULL_NAME full_name
;
627 char buffer
[MAX_PATHNAME_LEN
];
634 PROFILE
*tempProfile
;
636 /* First time around */
639 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
641 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
642 if(MRUProfile
[i
] == NULL
) break;
643 MRUProfile
[i
]->changed
=FALSE
;
644 MRUProfile
[i
]->section
=NULL
;
645 MRUProfile
[i
]->dos_name
=NULL
;
646 MRUProfile
[i
]->unix_name
=NULL
;
647 MRUProfile
[i
]->filename
=NULL
;
648 MRUProfile
[i
]->mtime
=0;
651 /* Check for a match */
653 if (strchrW( filename
, '/' ) || strchrW( filename
, '\\' ) ||
654 strchrW( filename
, ':' ))
656 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
660 static const WCHAR bkslashW
[] = {'\\',0};
661 WCHAR windirW
[MAX_PATH
];
663 GetWindowsDirectoryW( windirW
, MAX_PATH
);
664 strcatW( windirW
, bkslashW
);
665 strcatW( windirW
, filename
);
666 if (!DOSFS_GetFullName( windirW
, FALSE
, &full_name
)) return FALSE
;
669 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
671 if ((MRUProfile
[i
]->filename
&& !strcmpW( filename
, MRUProfile
[i
]->filename
)) ||
672 (MRUProfile
[i
]->dos_name
&& !strcmpW( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
677 tempProfile
=MRUProfile
[i
];
679 MRUProfile
[j
]=MRUProfile
[j
-1];
680 CurProfile
=tempProfile
;
682 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
683 TRACE("(%s): already opened (mru=%d)\n",
684 debugstr_w(filename
), i
);
686 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
687 debugstr_w(filename
), i
);
692 /* Flush the old current profile */
695 /* Make the oldest profile the current one only in order to get rid of it */
696 if(i
==N_CACHED_PROFILES
)
698 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
699 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
700 MRUProfile
[i
]=MRUProfile
[i
-1];
701 CurProfile
=tempProfile
;
703 if(CurProfile
->filename
) PROFILE_ReleaseFile();
705 /* OK, now that CurProfile is definitely free we assign it our new file */
706 newdos_name
= HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name
.short_name
)+1) * sizeof(WCHAR
) );
707 strcpyW( newdos_name
, full_name
.short_name
);
708 CurProfile
->dos_name
= newdos_name
;
709 CurProfile
->filename
= HeapAlloc( GetProcessHeap(), 0, (strlenW(filename
)+1) * sizeof(WCHAR
) );
710 strcpyW( CurProfile
->filename
, filename
);
712 /* Try to open the profile file, first in $HOME/.wine */
714 /* FIXME: this will need a more general solution */
715 strcpy( buffer
, wine_get_config_dir() );
716 p
= buffer
+ strlen(buffer
);
718 *p
= 0; /* make strlen() below happy */
719 name
= strrchrW( newdos_name
, '\\' ) + 1;
720 WideCharToMultiByte(DRIVE_GetCodepage(full_name
.drive
), 0, name
, -1,
721 p
, sizeof(buffer
) - strlen(buffer
), NULL
, NULL
);
722 if ((file
= fopen( buffer
, "r" )))
724 TRACE("(%s): found it in %s\n", debugstr_w(filename
), buffer
);
725 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(buffer
)+1 );
726 strcpy( CurProfile
->unix_name
, buffer
);
730 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.long_name
)+1 );
731 strcpy( CurProfile
->unix_name
, full_name
.long_name
);
732 if ((file
= fopen( full_name
.long_name
, "r" )))
733 TRACE("(%s): found it in %s\n",
734 debugstr_w(filename
), full_name
.long_name
);
739 CurProfile
->section
= PROFILE_Load( file
);
741 if(!stat(CurProfile
->unix_name
,&buf
))
742 CurProfile
->mtime
=buf
.st_mtime
;
746 /* Does not exist yet, we will create it in PROFILE_FlushFile */
747 WARN("profile file %s not found\n", debugstr_w(newdos_name
) );
753 /***********************************************************************
756 * Returns all keys of a section.
757 * If return_values is TRUE, also include the corresponding values.
759 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCWSTR section_name
,
760 LPWSTR buffer
, UINT len
, BOOL handle_env
,
765 if(!buffer
) return 0;
767 TRACE("%s,%p,%u\n", debugstr_w(section_name
), buffer
, len
);
771 if (section
->name
[0] && !strcmpiW( section
->name
, section_name
))
774 for (key
= section
->key
; key
; key
= key
->next
)
777 if (!*key
->name
) continue; /* Skip empty lines */
778 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
779 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
, 0 );
780 len
-= strlenW(buffer
) + 1;
781 buffer
+= strlenW(buffer
) + 1;
784 if (return_values
&& key
->value
) {
786 PROFILE_CopyEntry ( buffer
,
787 key
->value
, len
- 1, handle_env
, 0 );
788 len
-= strlenW(buffer
) + 1;
789 buffer
+= strlenW(buffer
) + 1;
794 /*If either lpszSection or lpszKey is NULL and the supplied
795 destination buffer is too small to hold all the strings,
796 the last string is truncated and followed by two null characters.
797 In this case, the return value is equal to cchReturnBuffer
805 section
= section
->next
;
807 buffer
[0] = buffer
[1] = '\0';
811 /* See GetPrivateProfileSectionNamesA for documentation */
812 static INT
PROFILE_GetSectionNames( LPWSTR buffer
, UINT len
)
816 PROFILESECTION
*section
;
827 section
= CurProfile
->section
;
828 while ((section
!=NULL
)) {
829 if (section
->name
[0]) {
830 l
= strlenW(section
->name
)+1;
833 strncpyW(buf
, section
->name
, f
-1);
840 strcpyW(buf
, section
->name
);
844 section
= section
->next
;
851 /***********************************************************************
854 * Get a profile string.
856 * Tests with GetPrivateProfileString16, W95a,
857 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
858 * section key_name def_val res buffer
859 * "set1" "1" "x" 43 [data]
860 * "set1" "1 " "x" 43 [data] (!)
861 * "set1" " 1 "' "x" 43 [data] (!)
862 * "set1" "" "x" 1 "x"
863 * "set1" "" "x " 1 "x" (!)
864 * "set1" "" " x " 3 " x" (!)
865 * "set1" NULL "x" 6 "1\02\03\0\0"
866 * "set1" "" "x" 1 "x"
867 * NULL "1" "x" 0 "" (!)
873 static INT
PROFILE_GetString( LPCWSTR section
, LPCWSTR key_name
,
874 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
876 PROFILEKEY
*key
= NULL
;
877 static const WCHAR empty_strW
[] = { 0 };
879 if(!buffer
) return 0;
881 if (!def_val
) def_val
= empty_strW
;
886 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
889 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
, FALSE
);
890 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
892 TRACE("(%s,%s,%s): returning %s\n",
893 debugstr_w(section
), debugstr_w(key_name
),
894 debugstr_w(def_val
), debugstr_w(buffer
) );
895 return strlenW( buffer
);
897 /* no "else" here ! */
898 if (section
&& section
[0])
900 INT ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
, FALSE
, FALSE
);
901 if (!buffer
[0]) /* no luck -> def_val */
903 PROFILE_CopyEntry(buffer
, def_val
, len
, FALSE
, TRUE
);
904 ret
= strlenW(buffer
);
913 /***********************************************************************
916 * Set a profile string.
918 static BOOL
PROFILE_SetString( LPCWSTR section_name
, LPCWSTR key_name
,
919 LPCWSTR value
, BOOL create_always
)
921 if (!key_name
) /* Delete a whole section */
923 TRACE("(%s)\n", debugstr_w(section_name
));
924 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
926 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
927 this is not an error on application's level.*/
929 else if (!value
) /* Delete a key */
931 TRACE("(%s,%s)\n", debugstr_w(section_name
), debugstr_w(key_name
) );
932 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
933 section_name
, key_name
);
934 return TRUE
; /* same error handling as above */
936 else /* Set the key value */
938 PROFILEKEY
*key
= PROFILE_Find(&CurProfile
->section
, section_name
,
939 key_name
, TRUE
, create_always
);
940 TRACE("(%s,%s,%s):\n",
941 debugstr_w(section_name
), debugstr_w(key_name
), debugstr_w(value
) );
942 if (!key
) return FALSE
;
945 /* strip the leading spaces. We can safely strip \n\r and
946 * friends too, they should not happen here anyway. */
947 while (PROFILE_isspace(*value
)) value
++;
949 if (!strcmpW( key
->value
, value
))
951 TRACE(" no change needed\n" );
952 return TRUE
; /* No change needed */
954 TRACE(" replacing %s\n", debugstr_w(key
->value
) );
955 HeapFree( GetProcessHeap(), 0, key
->value
);
957 else TRACE(" creating key\n" );
958 key
->value
= HeapAlloc( GetProcessHeap(), 0, (strlenW(value
)+1) * sizeof(WCHAR
) );
959 strcpyW( key
->value
, value
);
960 CurProfile
->changed
= TRUE
;
966 /***********************************************************************
967 * PROFILE_GetWineIniString
969 * Get a config string from the wine.ini file.
971 int PROFILE_GetWineIniString( LPCWSTR section
, LPCWSTR key_name
,
972 LPCWSTR def
, LPWSTR buffer
, int len
)
976 OBJECT_ATTRIBUTES attr
;
977 UNICODE_STRING nameW
;
979 attr
.Length
= sizeof(attr
);
980 attr
.RootDirectory
= wine_profile_key
;
981 attr
.ObjectName
= &nameW
;
983 attr
.SecurityDescriptor
= NULL
;
984 attr
.SecurityQualityOfService
= NULL
;
985 RtlInitUnicodeString( &nameW
, section
);
986 if (!(err
= NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
)))
988 char tmp
[PROFILE_MAX_LINE_LEN
*sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
991 RtlInitUnicodeString( &nameW
, key_name
);
992 if (!(err
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
993 tmp
, sizeof(tmp
), &count
)))
995 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
996 PROFILE_CopyEntry( buffer
, str
, len
, TRUE
, TRUE
);
1001 if (err
) PROFILE_CopyEntry( buffer
, def
, len
, TRUE
, TRUE
);
1002 TRACE( "(%s,%s,%s): returning %s\n", debugstr_w(section
),
1003 debugstr_w(key_name
), debugstr_w(def
), debugstr_w(buffer
) );
1004 return strlenW(buffer
);
1008 /******************************************************************************
1010 * PROFILE_GetWineIniBool
1012 * Reads a boolean value from the wine.ini file. This function attempts to
1013 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
1014 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
1015 * true. Anything else results in the return of the default value.
1017 * This function uses 1 to indicate true, and 0 for false. You can check
1018 * for existence by setting def to something other than 0 or 1 and
1019 * examining the return value.
1021 int PROFILE_GetWineIniBool( LPCWSTR section
, LPCWSTR key_name
, int def
)
1023 static const WCHAR def_valueW
[] = {'~',0};
1027 PROFILE_GetWineIniString(section
, key_name
, def_valueW
, key_value
, 2);
1029 switch(key_value
[0]) {
1050 TRACE("(%s, %s, %s), [%c], ret %s\n", debugstr_w(section
), debugstr_w(key_name
),
1051 def
? "TRUE" : "FALSE", key_value
[0],
1052 retval
? "TRUE" : "FALSE");
1058 /***********************************************************************
1059 * PROFILE_LoadWineIni
1061 * Load the old .winerc file.
1063 int PROFILE_LoadWineIni(void)
1065 OBJECT_ATTRIBUTES attr
;
1066 UNICODE_STRING nameW
;
1067 char buffer
[MAX_PATHNAME_LEN
];
1073 attr
.Length
= sizeof(attr
);
1074 attr
.RootDirectory
= 0;
1075 attr
.ObjectName
= &nameW
;
1076 attr
.Attributes
= 0;
1077 attr
.SecurityDescriptor
= NULL
;
1078 attr
.SecurityQualityOfService
= NULL
;
1080 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1081 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1082 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1084 ERR("Cannot create config registry key\n" );
1087 RtlFreeUnicodeString( &nameW
);
1090 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1091 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1092 NULL
, REG_OPTION_VOLATILE
, &disp
))
1094 ERR("Cannot create config registry key\n" );
1097 RtlFreeUnicodeString( &nameW
);
1099 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1101 if ((p
= getenv( "HOME" )) != NULL
)
1103 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1104 strcat( buffer
, PROFILE_WineIniName
);
1105 if ((f
= fopen( buffer
, "r" )) != NULL
)
1107 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1109 /* convert to the new format */
1110 sprintf( buffer
, "%s/config", wine_get_config_dir() );
1111 convert_config( f
, buffer
);
1114 MESSAGE( "The '%s' configuration file has been converted\n"
1115 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1116 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1117 "and then remove the old one and restart Wine.\n" );
1121 else WARN("could not get $HOME value for config file.\n" );
1123 MESSAGE( "Can't open configuration file %s/config\n", wine_get_config_dir() );
1128 /***********************************************************************
1129 * PROFILE_UsageWineIni
1131 * Explain the wine.ini file to those who don't read documentation.
1132 * Keep below one screenful in length so that error messages above are
1135 void PROFILE_UsageWineIni(void)
1137 MESSAGE("Perhaps you have not properly edited or created "
1138 "your Wine configuration file.\n");
1139 MESSAGE("This is (supposed to be) '%s/config'\n", wine_get_config_dir());
1140 /* RTFM, so to say */
1144 /********************* API functions **********************************/
1146 /***********************************************************************
1147 * GetProfileInt (KERNEL.57)
1149 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1151 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1155 /***********************************************************************
1156 * GetProfileIntA (KERNEL32.@)
1158 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1160 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1163 /***********************************************************************
1164 * GetProfileIntW (KERNEL32.@)
1166 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1168 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1172 * if allow_section_name_copy is TRUE, allow the copying :
1173 * - of Section names if 'section' is NULL
1174 * - of Keys in a Section if 'entry' is NULL
1175 * (see MSDN doc for GetPrivateProfileString)
1177 static int PROFILE_GetPrivateProfileString( LPCWSTR section
, LPCWSTR entry
,
1178 LPCWSTR def_val
, LPWSTR buffer
,
1179 UINT len
, LPCWSTR filename
,
1180 BOOL allow_section_name_copy
)
1183 LPWSTR pDefVal
= NULL
;
1188 TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section
), debugstr_w(entry
),
1189 debugstr_w(def_val
), buffer
, len
, debugstr_w(filename
));
1191 /* strip any trailing ' ' of def_val. */
1194 LPCWSTR p
= &def_val
[strlenW(def_val
)]; /* even "" works ! */
1202 if (*p
== ' ') /* ouch, contained trailing ' ' */
1204 int len
= (int)(p
- def_val
);
1205 pDefVal
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1206 strncpyW(pDefVal
, def_val
, len
);
1207 pDefVal
[len
] = '\0';
1211 pDefVal
= (LPWSTR
)def_val
;
1213 EnterCriticalSection( &PROFILE_CritSect
);
1215 if (PROFILE_Open( filename
)) {
1216 if ((allow_section_name_copy
) && (section
== NULL
))
1217 ret
= PROFILE_GetSectionNames(buffer
, len
);
1219 /* PROFILE_GetString already handles the 'entry == NULL' case */
1220 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1222 lstrcpynW( buffer
, pDefVal
, len
);
1223 ret
= strlenW( buffer
);
1226 LeaveCriticalSection( &PROFILE_CritSect
);
1228 if (pDefVal
!= def_val
) /* allocated */
1229 HeapFree(GetProcessHeap(), 0, pDefVal
);
1231 TRACE("returning %s, %d\n", debugstr_w(buffer
), ret
);
1236 /***********************************************************************
1237 * GetPrivateProfileString (KERNEL.128)
1239 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1240 LPCSTR def_val
, LPSTR buffer
,
1241 UINT16 len
, LPCSTR filename
)
1243 UNICODE_STRING sectionW
, entryW
, def_valW
, filenameW
;
1245 INT16 retW
, ret
= 0;
1247 bufferW
= buffer
? HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
)) : NULL
;
1248 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1249 else sectionW
.Buffer
= NULL
;
1250 if (entry
) RtlCreateUnicodeStringFromAsciiz(&entryW
, entry
);
1251 else entryW
.Buffer
= NULL
;
1252 if (def_val
) RtlCreateUnicodeStringFromAsciiz(&def_valW
, def_val
);
1253 else def_valW
.Buffer
= NULL
;
1254 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1255 else filenameW
.Buffer
= NULL
;
1257 retW
= PROFILE_GetPrivateProfileString( sectionW
.Buffer
, entryW
.Buffer
,
1258 def_valW
.Buffer
, bufferW
, len
,
1259 filenameW
.Buffer
, FALSE
);
1262 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, retW
+ 1, buffer
, len
, NULL
, NULL
);
1269 ret
--; /* strip terminating 0 */
1272 RtlFreeUnicodeString(§ionW
);
1273 RtlFreeUnicodeString(&entryW
);
1274 RtlFreeUnicodeString(&def_valW
);
1275 RtlFreeUnicodeString(&filenameW
);
1276 if (bufferW
) HeapFree(GetProcessHeap(), 0, bufferW
);
1280 /***********************************************************************
1281 * GetPrivateProfileStringA (KERNEL32.@)
1283 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1284 LPCSTR def_val
, LPSTR buffer
,
1285 UINT len
, LPCSTR filename
)
1287 UNICODE_STRING sectionW
, entryW
, def_valW
, filenameW
;
1291 bufferW
= buffer
? HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
)) : NULL
;
1292 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1293 else sectionW
.Buffer
= NULL
;
1294 if (entry
) RtlCreateUnicodeStringFromAsciiz(&entryW
, entry
);
1295 else entryW
.Buffer
= NULL
;
1296 if (def_val
) RtlCreateUnicodeStringFromAsciiz(&def_valW
, def_val
);
1297 else def_valW
.Buffer
= NULL
;
1298 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1299 else filenameW
.Buffer
= NULL
;
1301 retW
= GetPrivateProfileStringW( sectionW
.Buffer
, entryW
.Buffer
,
1302 def_valW
.Buffer
, bufferW
, len
,
1306 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, retW
+ 1, buffer
, len
, NULL
, NULL
);
1313 ret
--; /* strip terminating 0 */
1316 RtlFreeUnicodeString(§ionW
);
1317 RtlFreeUnicodeString(&entryW
);
1318 RtlFreeUnicodeString(&def_valW
);
1319 RtlFreeUnicodeString(&filenameW
);
1320 if (bufferW
) HeapFree(GetProcessHeap(), 0, bufferW
);
1324 /***********************************************************************
1325 * GetPrivateProfileStringW (KERNEL32.@)
1327 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1328 LPCWSTR def_val
, LPWSTR buffer
,
1329 UINT len
, LPCWSTR filename
)
1331 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1332 buffer
, len
, filename
, TRUE
);
1335 /***********************************************************************
1336 * GetProfileString (KERNEL.58)
1338 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1339 LPSTR buffer
, UINT16 len
)
1341 return GetPrivateProfileString16( section
, entry
, def_val
,
1342 buffer
, len
, "win.ini" );
1345 /***********************************************************************
1346 * GetProfileStringA (KERNEL32.@)
1348 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1349 LPSTR buffer
, UINT len
)
1351 return GetPrivateProfileStringA( section
, entry
, def_val
,
1352 buffer
, len
, "win.ini" );
1355 /***********************************************************************
1356 * GetProfileStringW (KERNEL32.@)
1358 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1359 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1361 return GetPrivateProfileStringW( section
, entry
, def_val
,
1362 buffer
, len
, wininiW
);
1365 /***********************************************************************
1366 * WriteProfileString (KERNEL.59)
1368 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1371 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1374 /***********************************************************************
1375 * WriteProfileStringA (KERNEL32.@)
1377 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1380 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1383 /***********************************************************************
1384 * WriteProfileStringW (KERNEL32.@)
1386 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1389 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1393 /***********************************************************************
1394 * GetPrivateProfileInt (KERNEL.127)
1396 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1397 INT16 def_val
, LPCSTR filename
)
1399 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1400 * here, but Win98SE doesn't care about this at all, so I deleted it.
1401 * AFAIR versions prior to Win9x had these limits, though. */
1402 return (INT16
)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1405 /***********************************************************************
1406 * GetPrivateProfileIntA (KERNEL32.@)
1408 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1409 INT def_val
, LPCSTR filename
)
1414 if (!GetPrivateProfileStringA( section
, entry
, "",
1415 buffer
, sizeof(buffer
), filename
))
1417 /* FIXME: if entry can be found but it's empty, then Win16 is
1418 * supposed to return 0 instead of def_val ! Difficult/problematic
1419 * to implement (every other failure also returns zero buffer),
1420 * thus wait until testing framework avail for making sure nothing
1421 * else gets broken that way. */
1422 if (!buffer
[0]) return (UINT
)def_val
;
1424 /* Don't use strtol() here !
1425 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1426 YES, scan for unsigned format ! (otherwise compatibility error) */
1427 if (!sscanf(buffer
, "%lu", &result
)) return 0;
1428 return (UINT
)result
;
1431 /***********************************************************************
1432 * GetPrivateProfileIntW (KERNEL32.@)
1434 * FIXME: rewrite using unicode
1436 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1437 INT def_val
, LPCWSTR filename
)
1439 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1440 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1441 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1442 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1443 HeapFree( GetProcessHeap(), 0, sectionA
);
1444 HeapFree( GetProcessHeap(), 0, filenameA
);
1445 HeapFree( GetProcessHeap(), 0, entryA
);
1449 /***********************************************************************
1450 * GetPrivateProfileSection (KERNEL.418)
1452 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1453 UINT16 len
, LPCSTR filename
)
1455 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1458 /***********************************************************************
1459 * GetPrivateProfileSectionW (KERNEL32.@)
1461 INT WINAPI
GetPrivateProfileSectionW( LPCWSTR section
, LPWSTR buffer
,
1462 DWORD len
, LPCWSTR filename
)
1466 EnterCriticalSection( &PROFILE_CritSect
);
1468 if (PROFILE_Open( filename
))
1469 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1472 LeaveCriticalSection( &PROFILE_CritSect
);
1477 /***********************************************************************
1478 * GetPrivateProfileSectionA (KERNEL32.@)
1480 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1481 DWORD len
, LPCSTR filename
)
1483 UNICODE_STRING sectionW
, filenameW
;
1487 bufferW
= buffer
? HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
)) : NULL
;
1488 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1489 else sectionW
.Buffer
= NULL
;
1490 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1491 else filenameW
.Buffer
= NULL
;
1493 retW
= GetPrivateProfileSectionW(sectionW
.Buffer
, bufferW
, len
, filenameW
.Buffer
);
1496 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, retW
+ 2, buffer
, len
, NULL
, NULL
);
1512 RtlFreeUnicodeString(§ionW
);
1513 RtlFreeUnicodeString(&filenameW
);
1514 if (bufferW
) HeapFree(GetProcessHeap(), 0, bufferW
);
1518 /***********************************************************************
1519 * GetProfileSection (KERNEL.419)
1521 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1523 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1526 /***********************************************************************
1527 * GetProfileSectionA (KERNEL32.@)
1529 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1531 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1534 /***********************************************************************
1535 * GetProfileSectionW (KERNEL32.@)
1537 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1539 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1543 /***********************************************************************
1544 * WritePrivateProfileString (KERNEL.129)
1546 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1547 LPCSTR string
, LPCSTR filename
)
1549 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1552 /***********************************************************************
1553 * WritePrivateProfileStringW (KERNEL32.@)
1555 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1556 LPCWSTR string
, LPCWSTR filename
)
1560 EnterCriticalSection( &PROFILE_CritSect
);
1562 if (PROFILE_Open( filename
))
1564 if (!section
&& !entry
&& !string
) /* documented "file flush" case */
1566 PROFILE_FlushFile();
1567 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1571 FIXME("(NULL?,%s,%s,%s)?\n",
1572 debugstr_w(entry
), debugstr_w(string
), debugstr_w(filename
));
1574 ret
= PROFILE_SetString( section
, entry
, string
, FALSE
);
1575 PROFILE_FlushFile();
1580 LeaveCriticalSection( &PROFILE_CritSect
);
1584 /***********************************************************************
1585 * WritePrivateProfileStringA (KERNEL32.@)
1587 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1588 LPCSTR string
, LPCSTR filename
)
1590 UNICODE_STRING sectionW
, entryW
, stringW
, filenameW
;
1593 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1594 else sectionW
.Buffer
= NULL
;
1595 if (entry
) RtlCreateUnicodeStringFromAsciiz(&entryW
, entry
);
1596 else entryW
.Buffer
= NULL
;
1597 if (string
) RtlCreateUnicodeStringFromAsciiz(&stringW
, string
);
1598 else stringW
.Buffer
= NULL
;
1599 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1600 else filenameW
.Buffer
= NULL
;
1602 ret
= WritePrivateProfileStringW(sectionW
.Buffer
, entryW
.Buffer
,
1603 stringW
.Buffer
, filenameW
.Buffer
);
1604 RtlFreeUnicodeString(§ionW
);
1605 RtlFreeUnicodeString(&entryW
);
1606 RtlFreeUnicodeString(&stringW
);
1607 RtlFreeUnicodeString(&filenameW
);
1611 /***********************************************************************
1612 * WritePrivateProfileSection (KERNEL.416)
1614 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1615 LPCSTR string
, LPCSTR filename
)
1617 return WritePrivateProfileSectionA( section
, string
, filename
);
1620 /***********************************************************************
1621 * WritePrivateProfileSectionW (KERNEL32.@)
1623 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1624 LPCWSTR string
, LPCWSTR filename
)
1629 EnterCriticalSection( &PROFILE_CritSect
);
1631 if (PROFILE_Open( filename
)) {
1632 if (!section
&& !string
)
1633 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1634 else if (!string
) {/* delete the named section*/
1635 ret
= PROFILE_SetString(section
,NULL
,NULL
, FALSE
);
1636 PROFILE_FlushFile();
1638 PROFILE_DeleteAllKeys(section
);
1641 LPWSTR buf
= HeapAlloc( GetProcessHeap(), 0, (strlenW(string
)+1) * sizeof(WCHAR
) );
1642 strcpyW( buf
, string
);
1643 if((p
= strchrW( buf
, '='))) {
1645 ret
= PROFILE_SetString( section
, buf
, p
+1, TRUE
);
1647 HeapFree( GetProcessHeap(), 0, buf
);
1648 string
+= strlenW(string
)+1;
1650 PROFILE_FlushFile();
1654 LeaveCriticalSection( &PROFILE_CritSect
);
1658 /***********************************************************************
1659 * WritePrivateProfileSectionA (KERNEL32.@)
1661 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1662 LPCSTR string
, LPCSTR filename
)
1665 UNICODE_STRING sectionW
, filenameW
;
1674 while(*p
) p
+= strlen(p
) + 1;
1675 lenA
= p
- string
+ 1;
1676 lenW
= MultiByteToWideChar(CP_ACP
, 0, string
, lenA
, NULL
, 0);
1677 if ((stringW
= HeapAlloc(GetProcessHeap(), 0, lenW
* sizeof(WCHAR
))))
1678 MultiByteToWideChar(CP_ACP
, 0, string
, lenA
, stringW
, lenW
);
1680 else stringW
= NULL
;
1681 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1682 else sectionW
.Buffer
= NULL
;
1683 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1684 else filenameW
.Buffer
= NULL
;
1686 ret
= WritePrivateProfileSectionW(sectionW
.Buffer
, stringW
, filenameW
.Buffer
);
1688 HeapFree(GetProcessHeap(), 0, stringW
);
1689 RtlFreeUnicodeString(§ionW
);
1690 RtlFreeUnicodeString(&filenameW
);
1694 /***********************************************************************
1695 * WriteProfileSection (KERNEL.417)
1697 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1699 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1702 /***********************************************************************
1703 * WriteProfileSectionA (KERNEL32.@)
1705 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1708 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1711 /***********************************************************************
1712 * WriteProfileSectionW (KERNEL32.@)
1714 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1716 return WritePrivateProfileSectionW(section
, keys_n_values
, wininiW
);
1719 /***********************************************************************
1720 * GetPrivateProfileSectionNames (KERNEL.143)
1722 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1725 return GetPrivateProfileSectionNamesA(buffer
,size
,filename
);
1729 /***********************************************************************
1730 * GetProfileSectionNames (KERNEL.142)
1732 WORD WINAPI
GetProfileSectionNames16(LPSTR buffer
, WORD size
)
1735 return GetPrivateProfileSectionNamesA(buffer
,size
,"win.ini");
1739 /***********************************************************************
1740 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1742 * Returns the section names contained in the specified file.
1743 * FIXME: Where do we find this file when the path is relative?
1744 * The section names are returned as a list of strings with an extra
1745 * '\0' to mark the end of the list. Except for that the behavior
1746 * depends on the Windows version.
1749 * - if the buffer is 0 or 1 character long then it is as if it was of
1751 * - otherwise, if the buffer is to small only the section names that fit
1753 * - note that this means if the buffer was to small to return even just
1754 * the first section name then a single '\0' will be returned.
1755 * - the return value is the number of characters written in the buffer,
1756 * except if the buffer was too smal in which case len-2 is returned
1759 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1760 * '\0' and the return value is 0
1761 * - otherwise if the buffer is too small then the first section name that
1762 * does not fit is truncated so that the string list can be terminated
1763 * correctly (double '\0')
1764 * - the return value is the number of characters written in the buffer
1765 * except for the trailing '\0'. If the buffer is too small, then the
1766 * return value is len-2
1767 * - Win2000 has a bug that triggers when the section names and the
1768 * trailing '\0' fit exactly in the buffer. In that case the trailing
1771 * Wine implements the observed Win2000 behavior (except for the bug).
1773 * Note that when the buffer is big enough then the return value may be any
1774 * value between 1 and len-1 (or len in Win95), including len-2.
1776 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1781 EnterCriticalSection( &PROFILE_CritSect
);
1783 if (PROFILE_Open( filename
))
1784 ret
= PROFILE_GetSectionNames(buffer
, size
);
1786 LeaveCriticalSection( &PROFILE_CritSect
);
1792 /***********************************************************************
1793 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1795 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1798 UNICODE_STRING filenameW
;
1802 bufferW
= buffer
? HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
)) : NULL
;
1803 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1804 else filenameW
.Buffer
= NULL
;
1806 retW
= GetPrivateProfileSectionNamesW(bufferW
, size
, filenameW
.Buffer
);
1809 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, retW
, buffer
, size
, NULL
, NULL
);
1817 RtlFreeUnicodeString(&filenameW
);
1818 if (bufferW
) HeapFree(GetProcessHeap(), 0, bufferW
);
1822 /***********************************************************************
1823 * GetPrivateProfileStruct (KERNEL.407)
1825 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1826 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1828 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1831 /***********************************************************************
1832 * GetPrivateProfileStructW (KERNEL32.@)
1834 * Should match Win95's behaviour pretty much
1836 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1837 LPVOID buf
, UINT len
, LPCWSTR filename
)
1841 EnterCriticalSection( &PROFILE_CritSect
);
1843 if (PROFILE_Open( filename
)) {
1844 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
, FALSE
);
1846 TRACE("value (at %p): %s\n", k
->value
, debugstr_w(k
->value
));
1847 if (((strlenW(k
->value
) - 2) / 2) == len
)
1854 end
= k
->value
+ strlenW(k
->value
); /* -> '\0' */
1855 /* check for invalid chars in ASCII coded hex string */
1856 for (p
=k
->value
; p
< end
; p
++)
1860 WARN("invalid char '%x' in file %s->[%s]->%s !\n",
1861 *p
, debugstr_w(filename
), debugstr_w(section
), debugstr_w(key
));
1868 BOOL highnibble
= TRUE
;
1870 LPBYTE binbuf
= (LPBYTE
)buf
;
1872 end
-= 2; /* don't include checksum in output data */
1873 /* translate ASCII hex format into binary data */
1874 for (p
=k
->value
; p
< end
; p
++)
1878 (c
- 'A' + 10) : (c
- '0');
1885 *binbuf
++ = b
; /* feed binary data into output */
1886 chksum
+= b
; /* calculate checksum */
1888 highnibble
^= 1; /* toggle */
1890 /* retrieve stored checksum value */
1892 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1894 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1895 if (b
== (chksum
& 0xff)) /* checksums match ? */
1901 LeaveCriticalSection( &PROFILE_CritSect
);
1906 /***********************************************************************
1907 * GetPrivateProfileStructA (KERNEL32.@)
1909 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1910 LPVOID buffer
, UINT len
, LPCSTR filename
)
1912 UNICODE_STRING sectionW
, keyW
, filenameW
;
1915 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1916 else sectionW
.Buffer
= NULL
;
1917 if (key
) RtlCreateUnicodeStringFromAsciiz(&keyW
, key
);
1918 else keyW
.Buffer
= NULL
;
1919 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1920 else filenameW
.Buffer
= NULL
;
1922 ret
= GetPrivateProfileStructW(sectionW
.Buffer
, keyW
.Buffer
, buffer
, len
,
1924 /* Do not translate binary data. */
1926 RtlFreeUnicodeString(§ionW
);
1927 RtlFreeUnicodeString(&keyW
);
1928 RtlFreeUnicodeString(&filenameW
);
1934 /***********************************************************************
1935 * WritePrivateProfileStruct (KERNEL.406)
1937 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1938 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1940 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1943 /***********************************************************************
1944 * WritePrivateProfileStructW (KERNEL32.@)
1946 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1947 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1951 LPWSTR outstring
, p
;
1954 if (!section
&& !key
&& !buf
) /* flush the cache */
1955 return WritePrivateProfileStringW( NULL
, NULL
, NULL
, filename
);
1957 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1958 outstring
= HeapAlloc( GetProcessHeap(), 0, (bufsize
*2 + 2 + 1) * sizeof(WCHAR
) );
1960 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1961 *p
++ = hex
[*binbuf
>> 4];
1962 *p
++ = hex
[*binbuf
& 0xf];
1965 /* checksum is sum & 0xff */
1966 *p
++ = hex
[(sum
& 0xf0) >> 4];
1967 *p
++ = hex
[sum
& 0xf];
1970 EnterCriticalSection( &PROFILE_CritSect
);
1972 if (PROFILE_Open( filename
)) {
1973 ret
= PROFILE_SetString( section
, key
, outstring
, FALSE
);
1974 PROFILE_FlushFile();
1977 LeaveCriticalSection( &PROFILE_CritSect
);
1979 HeapFree( GetProcessHeap(), 0, outstring
);
1984 /***********************************************************************
1985 * WritePrivateProfileStructA (KERNEL32.@)
1987 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1988 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1990 UNICODE_STRING sectionW
, keyW
, filenameW
;
1993 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1994 else sectionW
.Buffer
= NULL
;
1995 if (key
) RtlCreateUnicodeStringFromAsciiz(&keyW
, key
);
1996 else keyW
.Buffer
= NULL
;
1997 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1998 else filenameW
.Buffer
= NULL
;
2000 /* Do not translate binary data. */
2001 ret
= WritePrivateProfileStructW(sectionW
.Buffer
, keyW
.Buffer
, buf
, bufsize
,
2004 RtlFreeUnicodeString(§ionW
);
2005 RtlFreeUnicodeString(&keyW
);
2006 RtlFreeUnicodeString(&filenameW
);
2011 /***********************************************************************
2012 * WriteOutProfiles (KERNEL.315)
2014 void WINAPI
WriteOutProfiles16(void)
2016 EnterCriticalSection( &PROFILE_CritSect
);
2017 PROFILE_FlushFile();
2018 LeaveCriticalSection( &PROFILE_CritSect
);
2021 /***********************************************************************
2022 * CloseProfileUserMapping (KERNEL32.@)
2024 BOOL WINAPI
CloseProfileUserMapping(void) {
2025 FIXME("(), stub!\n");
2026 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);