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"
47 #include "wine/unicode.h"
48 #include "wine/server.h"
49 #include "wine/library.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(profile
);
54 typedef struct tagPROFILEKEY
57 struct tagPROFILEKEY
*next
;
61 typedef struct tagPROFILESECTION
63 struct tagPROFILEKEY
*key
;
64 struct tagPROFILESECTION
*next
;
72 PROFILESECTION
*section
;
80 #define N_CACHED_PROFILES 10
82 /* Cached profile files */
83 static PROFILE
*MRUProfile
[N_CACHED_PROFILES
]={NULL
};
85 #define CurProfile (MRUProfile[0])
87 /* wine.ini config file registry root */
88 static HKEY wine_profile_key
;
90 #define PROFILE_MAX_LINE_LEN 1024
92 /* Wine profile name in $HOME directory; must begin with slash */
93 static const char PROFILE_WineIniName
[] = "/.winerc";
95 /* Wine profile: the profile file being used */
96 static char PROFILE_WineIniUsed
[MAX_PATHNAME_LEN
] = "";
98 /* Check for comments in profile */
99 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
101 static const WCHAR wininiW
[] = { 'w','i','n','.','i','n','i',0 };
103 static CRITICAL_SECTION PROFILE_CritSect
= CRITICAL_SECTION_INIT("PROFILE_CritSect");
105 static const char hex
[16] = "0123456789ABCDEF";
107 /***********************************************************************
110 * Copy the content of an entry into a buffer, removing quotes, and possibly
111 * translating environment variables.
113 static void PROFILE_CopyEntry( LPWSTR buffer
, LPCWSTR value
, int len
,
114 int handle_env
, BOOL strip_quote
)
121 if (strip_quote
&& ((*value
== '\'') || (*value
== '\"')))
123 if (value
[1] && (value
[strlenW(value
)-1] == *value
)) quote
= *value
++;
128 lstrcpynW( buffer
, value
, len
);
129 if (quote
&& (len
>= strlenW(value
))) buffer
[strlenW(buffer
)-1] = '\0';
133 for (p
= value
; (*p
&& (len
> 1)); *buffer
++ = *p
++, len
-- )
135 if ((*p
== '$') && (p
[1] == '{'))
138 LPCWSTR p2
= strchrW( p
, '}' );
140 if (!p2
) continue; /* ignore it */
141 copy_len
= min( 1024, (int)(p2
-p
)-1 );
142 strncpyW(env_val
, p
+ 2, copy_len
);
143 env_val
[copy_len
- 1] = 0; /* ensure 0 termination */
145 if (GetEnvironmentVariableW( env_val
, buffer
, len
))
147 copy_len
= strlenW( buffer
);
154 if (quote
&& (len
> 1)) buffer
--;
159 /***********************************************************************
162 * Save a profile tree to a file.
164 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
167 char buffer
[PROFILE_MAX_LINE_LEN
];
169 for ( ; section
; section
= section
->next
)
171 if (section
->name
[0])
173 WideCharToMultiByte(CP_ACP
, 0, section
->name
, -1, buffer
, sizeof(buffer
), NULL
, NULL
);
174 fprintf( file
, "\r\n[%s]\r\n", buffer
);
176 for (key
= section
->key
; key
; key
= key
->next
)
178 WideCharToMultiByte(CP_ACP
, 0, key
->name
, -1, buffer
, sizeof(buffer
), NULL
, NULL
);
179 fprintf( file
, "%s", buffer
);
182 WideCharToMultiByte(CP_ACP
, 0, key
->value
, -1, buffer
, sizeof(buffer
), NULL
, NULL
);
183 fprintf( file
, "=%s", buffer
);
185 fprintf( file
, "\r\n" );
191 /***********************************************************************
194 * Free a profile tree.
196 static void PROFILE_Free( PROFILESECTION
*section
)
198 PROFILESECTION
*next_section
;
199 PROFILEKEY
*key
, *next_key
;
201 for ( ; section
; section
= next_section
)
203 for (key
= section
->key
; key
; key
= next_key
)
205 next_key
= key
->next
;
206 if (key
->value
) HeapFree( GetProcessHeap(), 0, key
->value
);
207 HeapFree( GetProcessHeap(), 0, key
);
209 next_section
= section
->next
;
210 HeapFree( GetProcessHeap(), 0, section
);
214 static inline int PROFILE_isspace(char c
)
216 if (isspace(c
)) return 1;
217 if (c
=='\r' || c
==0x1a) return 1;
218 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
223 /***********************************************************************
226 * Load a profile tree from a file.
228 static PROFILESECTION
*PROFILE_Load( FILE *file
)
230 char buffer
[PROFILE_MAX_LINE_LEN
];
233 PROFILESECTION
*section
, *first_section
;
234 PROFILESECTION
**next_section
;
235 PROFILEKEY
*key
, *prev_key
, **next_key
;
237 first_section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
238 if(first_section
== NULL
) return NULL
;
239 first_section
->name
[0] = 0;
240 first_section
->key
= NULL
;
241 first_section
->next
= NULL
;
242 next_section
= &first_section
->next
;
243 next_key
= &first_section
->key
;
246 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
250 while (*p
&& PROFILE_isspace(*p
)) p
++;
251 if (*p
== '[') /* section start */
253 if (!(p2
= strrchr( p
, ']' )))
255 WARN("Invalid section header at line %d: '%s'\n",
263 if (!(section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) + len
* sizeof(WCHAR
) )))
265 MultiByteToWideChar(CP_ACP
, 0, p
, -1, section
->name
, len
+ 1);
267 section
->next
= NULL
;
268 *next_section
= section
;
269 next_section
= §ion
->next
;
270 next_key
= §ion
->key
;
273 TRACE("New section: %s\n", debugstr_w(section
->name
));
280 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
282 if ((p2
= strchr( p
, '=' )) != NULL
)
285 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
287 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
290 if(*p
|| !prev_key
|| *prev_key
->name
)
293 if (!(key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) + len
* sizeof(WCHAR
) ))) break;
294 MultiByteToWideChar(CP_ACP
, 0, p
, -1, key
->name
, len
+ 1);
297 len
= strlen(p2
) + 1;
298 key
->value
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
299 MultiByteToWideChar(CP_ACP
, 0, p2
, -1, key
->value
, len
);
301 else key
->value
= NULL
;
305 next_key
= &key
->next
;
308 TRACE("New key: name=%s, value=%s\n",
309 debugstr_w(key
->name
), key
->value
? debugstr_w(key
->value
) : "(none)");
312 return first_section
;
315 /* convert the .winerc file to the new format */
316 static void convert_config( FILE *in
, const char *output_name
)
318 char buffer
[PROFILE_MAX_LINE_LEN
];
322 /* create the output file, only if it doesn't exist already */
323 int fd
= open( output_name
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666 );
326 MESSAGE( "Could not create new config file '%s': %s\n", output_name
, strerror(errno
) );
330 out
= fdopen( fd
, "w" );
331 fprintf( out
, "WINE REGISTRY Version 2\n" );
332 fprintf( out
, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
333 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, in
))
335 if (buffer
[strlen(buffer
)-1] == '\n') buffer
[strlen(buffer
)-1] = 0;
337 while (*p
&& PROFILE_isspace(*p
)) p
++;
338 if (*p
== '[') /* section start */
340 if ((p2
= strrchr( p
, ']' )))
344 fprintf( out
, "[%s]\n", p
);
349 if (*p
== ';' || *p
== '#')
351 fprintf( out
, "%s\n", p
);
356 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
358 if ((p2
= strchr( p
, '=' )) != NULL
)
361 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
363 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
368 fprintf( out
, "\n" );
374 if (*p
== '\\') fputc( '\\', out
);
378 fprintf( out
, "\" = \"" );
383 if (*p2
== '\\') fputc( '\\', out
);
388 fprintf( out
, "\"\n" );
394 /***********************************************************************
395 * PROFILE_DeleteSection
397 * Delete a section from a profile tree.
399 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCWSTR name
)
403 if ((*section
)->name
[0] && !strcmpiW( (*section
)->name
, name
))
405 PROFILESECTION
*to_del
= *section
;
406 *section
= to_del
->next
;
408 PROFILE_Free( to_del
);
411 section
= &(*section
)->next
;
417 /***********************************************************************
420 * Delete a key from a profile tree.
422 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
423 LPCWSTR section_name
, LPCWSTR key_name
)
427 if ((*section
)->name
[0] && !strcmpiW( (*section
)->name
, section_name
))
429 PROFILEKEY
**key
= &(*section
)->key
;
432 if (!strcmpiW( (*key
)->name
, key_name
))
434 PROFILEKEY
*to_del
= *key
;
436 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
437 HeapFree( GetProcessHeap(), 0, to_del
);
443 section
= &(*section
)->next
;
449 /***********************************************************************
450 * PROFILE_DeleteAllKeys
452 * Delete all keys from a profile tree.
454 void PROFILE_DeleteAllKeys( LPCWSTR section_name
)
456 PROFILESECTION
**section
= &CurProfile
->section
;
459 if ((*section
)->name
[0] && !strcmpiW( (*section
)->name
, section_name
))
461 PROFILEKEY
**key
= &(*section
)->key
;
464 PROFILEKEY
*to_del
= *key
;
466 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
467 HeapFree( GetProcessHeap(), 0, to_del
);
468 CurProfile
->changed
=TRUE
;
471 section
= &(*section
)->next
;
476 /***********************************************************************
479 * Find a key in a profile tree, optionally creating it.
481 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
, LPCWSTR section_name
,
482 LPCWSTR key_name
, BOOL create
, BOOL create_always
)
487 while (PROFILE_isspace(*section_name
)) section_name
++;
488 p
= section_name
+ strlenW(section_name
) - 1;
489 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
490 seclen
= p
- section_name
+ 1;
492 while (PROFILE_isspace(*key_name
)) key_name
++;
493 p
= key_name
+ strlenW(key_name
) - 1;
494 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
495 keylen
= p
- key_name
+ 1;
499 if ( ((*section
)->name
[0])
500 && (!(strncmpiW( (*section
)->name
, section_name
, seclen
)))
501 && (((*section
)->name
)[seclen
] == '\0') )
503 PROFILEKEY
**key
= &(*section
)->key
;
507 /* If create_always is FALSE then we check if the keyname already exists.
508 * Otherwise we add it regardless of its existence, to allow
509 * keys to be added more then once in some cases.
513 if ( (!(strncmpiW( (*key
)->name
, key_name
, keylen
)))
514 && (((*key
)->name
)[keylen
] == '\0') )
519 if (!create
) return NULL
;
520 if (!(*key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) + strlenW(key_name
) * sizeof(WCHAR
) )))
522 strcpyW( (*key
)->name
, key_name
);
523 (*key
)->value
= NULL
;
527 section
= &(*section
)->next
;
529 if (!create
) return NULL
;
530 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) + strlenW(section_name
) * sizeof(WCHAR
) );
531 if(*section
== NULL
) return NULL
;
532 strcpyW( (*section
)->name
, section_name
);
533 (*section
)->next
= NULL
;
534 if (!((*section
)->key
= HeapAlloc( GetProcessHeap(), 0,
535 sizeof(PROFILEKEY
) + strlenW(key_name
) * sizeof(WCHAR
) )))
537 HeapFree(GetProcessHeap(), 0, *section
);
540 strcpyW( (*section
)->key
->name
, key_name
);
541 (*section
)->key
->value
= NULL
;
542 (*section
)->key
->next
= NULL
;
543 return (*section
)->key
;
547 /***********************************************************************
550 * Flush the current profile to disk if changed.
552 static BOOL
PROFILE_FlushFile(void)
554 char *p
, buffer
[MAX_PATHNAME_LEN
];
555 const char *unix_name
;
561 WARN("No current profile!\n");
565 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
566 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
568 int drive
= toupperW(CurProfile
->dos_name
[0]) - 'A';
570 /* Try to create it in $HOME/.wine */
571 /* FIXME: this will need a more general solution */
572 strcpy( buffer
, wine_get_config_dir() );
573 p
= buffer
+ strlen(buffer
);
575 *p
= 0; /* make strlen() below happy */
576 name
= strrchrW( CurProfile
->dos_name
, '\\' ) + 1;
577 WideCharToMultiByte(DRIVE_GetCodepage(drive
), 0, name
, -1,
578 p
, sizeof(buffer
) - strlen(buffer
), NULL
, NULL
);
579 file
= fopen( buffer
, "w" );
585 WARN("could not save profile file %s\n", debugstr_w(CurProfile
->dos_name
));
589 TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile
->dos_name
), unix_name
);
590 PROFILE_Save( file
, CurProfile
->section
);
592 CurProfile
->changed
= FALSE
;
593 if(!stat(unix_name
,&buf
))
594 CurProfile
->mtime
=buf
.st_mtime
;
599 /***********************************************************************
600 * PROFILE_ReleaseFile
602 * Flush the current profile to disk and remove it from the cache.
604 static void PROFILE_ReleaseFile(void)
607 PROFILE_Free( CurProfile
->section
);
608 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
609 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
610 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
611 CurProfile
->changed
= FALSE
;
612 CurProfile
->section
= NULL
;
613 CurProfile
->dos_name
= NULL
;
614 CurProfile
->unix_name
= NULL
;
615 CurProfile
->filename
= NULL
;
616 CurProfile
->mtime
= 0;
620 /***********************************************************************
623 * Open a profile file, checking the cached file first.
625 static BOOL
PROFILE_Open( LPCWSTR filename
)
627 DOS_FULL_NAME full_name
;
628 char buffer
[MAX_PATHNAME_LEN
];
635 PROFILE
*tempProfile
;
637 /* First time around */
640 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
642 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
643 if(MRUProfile
[i
] == NULL
) break;
644 MRUProfile
[i
]->changed
=FALSE
;
645 MRUProfile
[i
]->section
=NULL
;
646 MRUProfile
[i
]->dos_name
=NULL
;
647 MRUProfile
[i
]->unix_name
=NULL
;
648 MRUProfile
[i
]->filename
=NULL
;
649 MRUProfile
[i
]->mtime
=0;
652 /* Check for a match */
654 if (strchrW( filename
, '/' ) || strchrW( filename
, '\\' ) ||
655 strchrW( filename
, ':' ))
657 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
661 static const WCHAR bkslashW
[] = {'\\',0};
662 WCHAR windirW
[MAX_PATH
];
664 GetWindowsDirectoryW( windirW
, MAX_PATH
);
665 strcatW( windirW
, bkslashW
);
666 strcatW( windirW
, filename
);
667 if (!DOSFS_GetFullName( windirW
, FALSE
, &full_name
)) return FALSE
;
670 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
672 if ((MRUProfile
[i
]->filename
&& !strcmpW( filename
, MRUProfile
[i
]->filename
)) ||
673 (MRUProfile
[i
]->dos_name
&& !strcmpW( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
678 tempProfile
=MRUProfile
[i
];
680 MRUProfile
[j
]=MRUProfile
[j
-1];
681 CurProfile
=tempProfile
;
683 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
684 TRACE("(%s): already opened (mru=%d)\n",
685 debugstr_w(filename
), i
);
687 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
688 debugstr_w(filename
), i
);
693 /* Flush the old current profile */
696 /* Make the oldest profile the current one only in order to get rid of it */
697 if(i
==N_CACHED_PROFILES
)
699 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
700 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
701 MRUProfile
[i
]=MRUProfile
[i
-1];
702 CurProfile
=tempProfile
;
704 if(CurProfile
->filename
) PROFILE_ReleaseFile();
706 /* OK, now that CurProfile is definitely free we assign it our new file */
707 newdos_name
= HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name
.short_name
)+1) * sizeof(WCHAR
) );
708 strcpyW( newdos_name
, full_name
.short_name
);
709 CurProfile
->dos_name
= newdos_name
;
710 CurProfile
->filename
= HeapAlloc( GetProcessHeap(), 0, (strlenW(filename
)+1) * sizeof(WCHAR
) );
711 strcpyW( CurProfile
->filename
, filename
);
713 /* Try to open the profile file, first in $HOME/.wine */
715 /* FIXME: this will need a more general solution */
716 strcpy( buffer
, wine_get_config_dir() );
717 p
= buffer
+ strlen(buffer
);
719 *p
= 0; /* make strlen() below happy */
720 name
= strrchrW( newdos_name
, '\\' ) + 1;
721 WideCharToMultiByte(DRIVE_GetCodepage(full_name
.drive
), 0, name
, -1,
722 p
, sizeof(buffer
) - strlen(buffer
), NULL
, NULL
);
723 if ((file
= fopen( buffer
, "r" )))
725 TRACE("(%s): found it in %s\n", debugstr_w(filename
), buffer
);
726 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(buffer
)+1 );
727 strcpy( CurProfile
->unix_name
, buffer
);
731 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.long_name
)+1 );
732 strcpy( CurProfile
->unix_name
, full_name
.long_name
);
733 if ((file
= fopen( full_name
.long_name
, "r" )))
734 TRACE("(%s): found it in %s\n",
735 debugstr_w(filename
), full_name
.long_name
);
740 CurProfile
->section
= PROFILE_Load( file
);
742 if(!stat(CurProfile
->unix_name
,&buf
))
743 CurProfile
->mtime
=buf
.st_mtime
;
747 /* Does not exist yet, we will create it in PROFILE_FlushFile */
748 WARN("profile file %s not found\n", debugstr_w(newdos_name
) );
754 /***********************************************************************
757 * Returns all keys of a section.
758 * If return_values is TRUE, also include the corresponding values.
760 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCWSTR section_name
,
761 LPWSTR buffer
, UINT len
, BOOL handle_env
,
766 if(!buffer
) return 0;
768 TRACE("%s,%p,%u\n", debugstr_w(section_name
), buffer
, len
);
772 if (section
->name
[0] && !strcmpiW( section
->name
, section_name
))
775 for (key
= section
->key
; key
; key
= key
->next
)
778 if (!*key
->name
) continue; /* Skip empty lines */
779 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
780 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
, 0 );
781 len
-= strlenW(buffer
) + 1;
782 buffer
+= strlenW(buffer
) + 1;
785 if (return_values
&& key
->value
) {
787 PROFILE_CopyEntry ( buffer
,
788 key
->value
, len
- 1, handle_env
, 0 );
789 len
-= strlenW(buffer
) + 1;
790 buffer
+= strlenW(buffer
) + 1;
795 /*If either lpszSection or lpszKey is NULL and the supplied
796 destination buffer is too small to hold all the strings,
797 the last string is truncated and followed by two null characters.
798 In this case, the return value is equal to cchReturnBuffer
806 section
= section
->next
;
808 buffer
[0] = buffer
[1] = '\0';
812 /* See GetPrivateProfileSectionNamesA for documentation */
813 static INT
PROFILE_GetSectionNames( LPWSTR buffer
, UINT len
)
817 PROFILESECTION
*section
;
828 section
= CurProfile
->section
;
829 while ((section
!=NULL
)) {
830 if (section
->name
[0]) {
831 l
= strlenW(section
->name
)+1;
834 strncpyW(buf
, section
->name
, f
-1);
841 strcpyW(buf
, section
->name
);
845 section
= section
->next
;
852 /***********************************************************************
855 * Get a profile string.
857 * Tests with GetPrivateProfileString16, W95a,
858 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
859 * section key_name def_val res buffer
860 * "set1" "1" "x" 43 [data]
861 * "set1" "1 " "x" 43 [data] (!)
862 * "set1" " 1 "' "x" 43 [data] (!)
863 * "set1" "" "x" 1 "x"
864 * "set1" "" "x " 1 "x" (!)
865 * "set1" "" " x " 3 " x" (!)
866 * "set1" NULL "x" 6 "1\02\03\0\0"
867 * "set1" "" "x" 1 "x"
868 * NULL "1" "x" 0 "" (!)
874 static INT
PROFILE_GetString( LPCWSTR section
, LPCWSTR key_name
,
875 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
877 PROFILEKEY
*key
= NULL
;
878 static const WCHAR empty_strW
[] = { 0 };
880 if(!buffer
) return 0;
882 if (!def_val
) def_val
= empty_strW
;
887 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
890 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
, FALSE
);
891 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
893 TRACE("(%s,%s,%s): returning %s\n",
894 debugstr_w(section
), debugstr_w(key_name
),
895 debugstr_w(def_val
), debugstr_w(buffer
) );
896 return strlenW( buffer
);
898 /* no "else" here ! */
899 if (section
&& section
[0])
901 INT ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
, FALSE
, FALSE
);
902 if (!buffer
[0]) /* no luck -> def_val */
904 PROFILE_CopyEntry(buffer
, def_val
, len
, FALSE
, TRUE
);
905 ret
= strlenW(buffer
);
914 /***********************************************************************
917 * Set a profile string.
919 static BOOL
PROFILE_SetString( LPCWSTR section_name
, LPCWSTR key_name
,
920 LPCWSTR value
, BOOL create_always
)
922 if (!key_name
) /* Delete a whole section */
924 TRACE("(%s)\n", debugstr_w(section_name
));
925 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
927 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
928 this is not an error on application's level.*/
930 else if (!value
) /* Delete a key */
932 TRACE("(%s,%s)\n", debugstr_w(section_name
), debugstr_w(key_name
) );
933 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
934 section_name
, key_name
);
935 return TRUE
; /* same error handling as above */
937 else /* Set the key value */
939 PROFILEKEY
*key
= PROFILE_Find(&CurProfile
->section
, section_name
,
940 key_name
, TRUE
, create_always
);
941 TRACE("(%s,%s,%s):\n",
942 debugstr_w(section_name
), debugstr_w(key_name
), debugstr_w(value
) );
943 if (!key
) return FALSE
;
946 /* strip the leading spaces. We can safely strip \n\r and
947 * friends too, they should not happen here anyway. */
948 while (PROFILE_isspace(*value
)) value
++;
950 if (!strcmpW( key
->value
, value
))
952 TRACE(" no change needed\n" );
953 return TRUE
; /* No change needed */
955 TRACE(" replacing %s\n", debugstr_w(key
->value
) );
956 HeapFree( GetProcessHeap(), 0, key
->value
);
958 else TRACE(" creating key\n" );
959 key
->value
= HeapAlloc( GetProcessHeap(), 0, (strlenW(value
)+1) * sizeof(WCHAR
) );
960 strcpyW( key
->value
, value
);
961 CurProfile
->changed
= TRUE
;
967 /***********************************************************************
968 * PROFILE_GetWineIniString
970 * Get a config string from the wine.ini file.
972 int PROFILE_GetWineIniString( LPCWSTR section
, LPCWSTR key_name
,
973 LPCWSTR def
, LPWSTR buffer
, int len
)
975 WCHAR tmp
[PROFILE_MAX_LINE_LEN
];
979 if (!(err
= RegOpenKeyW( wine_profile_key
, section
, &hkey
)))
982 DWORD count
= sizeof(tmp
);
983 err
= RegQueryValueExW( hkey
, key_name
, 0, &type
, (LPBYTE
)tmp
, &count
);
987 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
, TRUE
);
988 TRACE( "(%s,%s,%s): returning %s\n", debugstr_w(section
),
989 debugstr_w(key_name
), debugstr_w(def
), debugstr_w(buffer
) );
990 return strlenW(buffer
);
994 /******************************************************************************
996 * PROFILE_GetWineIniBool
998 * Reads a boolean value from the wine.ini file. This function attempts to
999 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
1000 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
1001 * true. Anything else results in the return of the default value.
1003 * This function uses 1 to indicate true, and 0 for false. You can check
1004 * for existence by setting def to something other than 0 or 1 and
1005 * examining the return value.
1007 int PROFILE_GetWineIniBool( LPCWSTR section
, LPCWSTR key_name
, int def
)
1009 static const WCHAR def_valueW
[] = {'~',0};
1013 PROFILE_GetWineIniString(section
, key_name
, def_valueW
, key_value
, 2);
1015 switch(key_value
[0]) {
1036 TRACE("(%s, %s, %s), [%c], ret %s\n", debugstr_w(section
), debugstr_w(key_name
),
1037 def
? "TRUE" : "FALSE", key_value
[0],
1038 retval
? "TRUE" : "FALSE");
1044 /***********************************************************************
1045 * PROFILE_LoadWineIni
1047 * Load the old .winerc file.
1049 int PROFILE_LoadWineIni(void)
1051 OBJECT_ATTRIBUTES attr
;
1052 UNICODE_STRING nameW
;
1053 char buffer
[MAX_PATHNAME_LEN
];
1059 attr
.Length
= sizeof(attr
);
1060 attr
.RootDirectory
= 0;
1061 attr
.ObjectName
= &nameW
;
1062 attr
.Attributes
= 0;
1063 attr
.SecurityDescriptor
= NULL
;
1064 attr
.SecurityQualityOfService
= NULL
;
1066 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1067 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1068 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1070 ERR("Cannot create config registry key\n" );
1073 RtlFreeUnicodeString( &nameW
);
1076 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1077 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1078 NULL
, REG_OPTION_VOLATILE
, &disp
))
1080 ERR("Cannot create config registry key\n" );
1083 RtlFreeUnicodeString( &nameW
);
1085 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1087 if ((p
= getenv( "HOME" )) != NULL
)
1089 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1090 strcat( buffer
, PROFILE_WineIniName
);
1091 if ((f
= fopen( buffer
, "r" )) != NULL
)
1093 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1095 /* convert to the new format */
1096 sprintf( buffer
, "%s/config", wine_get_config_dir() );
1097 convert_config( f
, buffer
);
1100 MESSAGE( "The '%s' configuration file has been converted\n"
1101 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1102 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1103 "and then remove the old one and restart Wine.\n" );
1107 else WARN("could not get $HOME value for config file.\n" );
1109 MESSAGE( "Can't open configuration file %s/config\n", wine_get_config_dir() );
1114 /***********************************************************************
1115 * PROFILE_UsageWineIni
1117 * Explain the wine.ini file to those who don't read documentation.
1118 * Keep below one screenful in length so that error messages above are
1121 void PROFILE_UsageWineIni(void)
1123 MESSAGE("Perhaps you have not properly edited or created "
1124 "your Wine configuration file.\n");
1125 MESSAGE("This is (supposed to be) '%s/config'\n", wine_get_config_dir());
1126 /* RTFM, so to say */
1130 /********************* API functions **********************************/
1132 /***********************************************************************
1133 * GetProfileInt (KERNEL.57)
1135 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1137 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1141 /***********************************************************************
1142 * GetProfileIntA (KERNEL32.@)
1144 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1146 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1149 /***********************************************************************
1150 * GetProfileIntW (KERNEL32.@)
1152 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1154 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1158 * if allow_section_name_copy is TRUE, allow the copying :
1159 * - of Section names if 'section' is NULL
1160 * - of Keys in a Section if 'entry' is NULL
1161 * (see MSDN doc for GetPrivateProfileString)
1163 static int PROFILE_GetPrivateProfileString( LPCWSTR section
, LPCWSTR entry
,
1164 LPCWSTR def_val
, LPWSTR buffer
,
1165 UINT len
, LPCWSTR filename
,
1166 BOOL allow_section_name_copy
)
1169 LPWSTR pDefVal
= NULL
;
1174 TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section
), debugstr_w(entry
),
1175 debugstr_w(def_val
), buffer
, len
, debugstr_w(filename
));
1177 /* strip any trailing ' ' of def_val. */
1180 LPCWSTR p
= &def_val
[strlenW(def_val
)]; /* even "" works ! */
1188 if (*p
== ' ') /* ouch, contained trailing ' ' */
1190 int len
= (int)(p
- def_val
);
1191 pDefVal
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1192 strncpyW(pDefVal
, def_val
, len
);
1193 pDefVal
[len
] = '\0';
1197 pDefVal
= (LPWSTR
)def_val
;
1199 EnterCriticalSection( &PROFILE_CritSect
);
1201 if (PROFILE_Open( filename
)) {
1202 if ((allow_section_name_copy
) && (section
== NULL
))
1203 ret
= PROFILE_GetSectionNames(buffer
, len
);
1205 /* PROFILE_GetString already handles the 'entry == NULL' case */
1206 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1208 lstrcpynW( buffer
, pDefVal
, len
);
1209 ret
= strlenW( buffer
);
1212 LeaveCriticalSection( &PROFILE_CritSect
);
1214 if (pDefVal
!= def_val
) /* allocated */
1215 HeapFree(GetProcessHeap(), 0, pDefVal
);
1217 TRACE("returning %s, %d\n", debugstr_w(buffer
), ret
);
1222 /***********************************************************************
1223 * GetPrivateProfileString (KERNEL.128)
1225 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1226 LPCSTR def_val
, LPSTR buffer
,
1227 UINT16 len
, LPCSTR filename
)
1229 UNICODE_STRING sectionW
, entryW
, def_valW
, filenameW
;
1231 INT16 retW
, ret
= 0;
1233 bufferW
= buffer
? HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
)) : NULL
;
1234 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1235 else sectionW
.Buffer
= NULL
;
1236 if (entry
) RtlCreateUnicodeStringFromAsciiz(&entryW
, entry
);
1237 else entryW
.Buffer
= NULL
;
1238 if (def_val
) RtlCreateUnicodeStringFromAsciiz(&def_valW
, def_val
);
1239 else def_valW
.Buffer
= NULL
;
1240 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1241 else filenameW
.Buffer
= NULL
;
1243 retW
= PROFILE_GetPrivateProfileString( sectionW
.Buffer
, entryW
.Buffer
,
1244 def_valW
.Buffer
, bufferW
, len
,
1245 filenameW
.Buffer
, FALSE
);
1248 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, retW
+ 1, buffer
, len
, NULL
, NULL
);
1255 ret
--; /* strip terminating 0 */
1258 RtlFreeUnicodeString(§ionW
);
1259 RtlFreeUnicodeString(&entryW
);
1260 RtlFreeUnicodeString(&def_valW
);
1261 RtlFreeUnicodeString(&filenameW
);
1262 if (bufferW
) HeapFree(GetProcessHeap(), 0, bufferW
);
1266 /***********************************************************************
1267 * GetPrivateProfileStringA (KERNEL32.@)
1269 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1270 LPCSTR def_val
, LPSTR buffer
,
1271 UINT len
, LPCSTR filename
)
1273 UNICODE_STRING sectionW
, entryW
, def_valW
, filenameW
;
1277 bufferW
= buffer
? HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
)) : NULL
;
1278 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1279 else sectionW
.Buffer
= NULL
;
1280 if (entry
) RtlCreateUnicodeStringFromAsciiz(&entryW
, entry
);
1281 else entryW
.Buffer
= NULL
;
1282 if (def_val
) RtlCreateUnicodeStringFromAsciiz(&def_valW
, def_val
);
1283 else def_valW
.Buffer
= NULL
;
1284 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1285 else filenameW
.Buffer
= NULL
;
1287 retW
= GetPrivateProfileStringW( sectionW
.Buffer
, entryW
.Buffer
,
1288 def_valW
.Buffer
, bufferW
, len
,
1292 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, retW
+ 1, buffer
, len
, NULL
, NULL
);
1299 ret
--; /* strip terminating 0 */
1302 RtlFreeUnicodeString(§ionW
);
1303 RtlFreeUnicodeString(&entryW
);
1304 RtlFreeUnicodeString(&def_valW
);
1305 RtlFreeUnicodeString(&filenameW
);
1306 if (bufferW
) HeapFree(GetProcessHeap(), 0, bufferW
);
1310 /***********************************************************************
1311 * GetPrivateProfileStringW (KERNEL32.@)
1313 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1314 LPCWSTR def_val
, LPWSTR buffer
,
1315 UINT len
, LPCWSTR filename
)
1317 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1318 buffer
, len
, filename
, TRUE
);
1321 /***********************************************************************
1322 * GetProfileString (KERNEL.58)
1324 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1325 LPSTR buffer
, UINT16 len
)
1327 return GetPrivateProfileString16( section
, entry
, def_val
,
1328 buffer
, len
, "win.ini" );
1331 /***********************************************************************
1332 * GetProfileStringA (KERNEL32.@)
1334 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1335 LPSTR buffer
, UINT len
)
1337 return GetPrivateProfileStringA( section
, entry
, def_val
,
1338 buffer
, len
, "win.ini" );
1341 /***********************************************************************
1342 * GetProfileStringW (KERNEL32.@)
1344 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1345 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1347 return GetPrivateProfileStringW( section
, entry
, def_val
,
1348 buffer
, len
, wininiW
);
1351 /***********************************************************************
1352 * WriteProfileString (KERNEL.59)
1354 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1357 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1360 /***********************************************************************
1361 * WriteProfileStringA (KERNEL32.@)
1363 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1366 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1369 /***********************************************************************
1370 * WriteProfileStringW (KERNEL32.@)
1372 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1375 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1379 /***********************************************************************
1380 * GetPrivateProfileInt (KERNEL.127)
1382 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1383 INT16 def_val
, LPCSTR filename
)
1385 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1386 * here, but Win98SE doesn't care about this at all, so I deleted it.
1387 * AFAIR versions prior to Win9x had these limits, though. */
1388 return (INT16
)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1391 /***********************************************************************
1392 * GetPrivateProfileIntA (KERNEL32.@)
1394 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1395 INT def_val
, LPCSTR filename
)
1400 if (!GetPrivateProfileStringA( section
, entry
, "",
1401 buffer
, sizeof(buffer
), filename
))
1403 /* FIXME: if entry can be found but it's empty, then Win16 is
1404 * supposed to return 0 instead of def_val ! Difficult/problematic
1405 * to implement (every other failure also returns zero buffer),
1406 * thus wait until testing framework avail for making sure nothing
1407 * else gets broken that way. */
1408 if (!buffer
[0]) return (UINT
)def_val
;
1410 /* Don't use strtol() here !
1411 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1412 YES, scan for unsigned format ! (otherwise compatibility error) */
1413 if (!sscanf(buffer
, "%lu", &result
)) return 0;
1414 return (UINT
)result
;
1417 /***********************************************************************
1418 * GetPrivateProfileIntW (KERNEL32.@)
1420 * FIXME: rewrite using unicode
1422 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1423 INT def_val
, LPCWSTR filename
)
1425 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1426 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1427 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1428 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1429 HeapFree( GetProcessHeap(), 0, sectionA
);
1430 HeapFree( GetProcessHeap(), 0, filenameA
);
1431 HeapFree( GetProcessHeap(), 0, entryA
);
1435 /***********************************************************************
1436 * GetPrivateProfileSection (KERNEL.418)
1438 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1439 UINT16 len
, LPCSTR filename
)
1441 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1444 /***********************************************************************
1445 * GetPrivateProfileSectionW (KERNEL32.@)
1447 INT WINAPI
GetPrivateProfileSectionW( LPCWSTR section
, LPWSTR buffer
,
1448 DWORD len
, LPCWSTR filename
)
1452 EnterCriticalSection( &PROFILE_CritSect
);
1454 if (PROFILE_Open( filename
))
1455 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1458 LeaveCriticalSection( &PROFILE_CritSect
);
1463 /***********************************************************************
1464 * GetPrivateProfileSectionA (KERNEL32.@)
1466 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1467 DWORD len
, LPCSTR filename
)
1469 UNICODE_STRING sectionW
, filenameW
;
1473 bufferW
= buffer
? HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
)) : NULL
;
1474 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1475 else sectionW
.Buffer
= NULL
;
1476 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1477 else filenameW
.Buffer
= NULL
;
1479 retW
= GetPrivateProfileSectionW(sectionW
.Buffer
, bufferW
, len
, filenameW
.Buffer
);
1482 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, retW
+ 2, buffer
, len
, NULL
, NULL
);
1498 RtlFreeUnicodeString(§ionW
);
1499 RtlFreeUnicodeString(&filenameW
);
1500 if (bufferW
) HeapFree(GetProcessHeap(), 0, bufferW
);
1504 /***********************************************************************
1505 * GetProfileSection (KERNEL.419)
1507 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1509 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1512 /***********************************************************************
1513 * GetProfileSectionA (KERNEL32.@)
1515 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1517 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1520 /***********************************************************************
1521 * GetProfileSectionW (KERNEL32.@)
1523 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1525 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1529 /***********************************************************************
1530 * WritePrivateProfileString (KERNEL.129)
1532 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1533 LPCSTR string
, LPCSTR filename
)
1535 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1538 /***********************************************************************
1539 * WritePrivateProfileStringW (KERNEL32.@)
1541 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1542 LPCWSTR string
, LPCWSTR filename
)
1546 EnterCriticalSection( &PROFILE_CritSect
);
1548 if (PROFILE_Open( filename
))
1550 if (!section
&& !entry
&& !string
) /* documented "file flush" case */
1552 PROFILE_FlushFile();
1553 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1557 FIXME("(NULL?,%s,%s,%s)?\n",
1558 debugstr_w(entry
), debugstr_w(string
), debugstr_w(filename
));
1560 ret
= PROFILE_SetString( section
, entry
, string
, FALSE
);
1561 PROFILE_FlushFile();
1566 LeaveCriticalSection( &PROFILE_CritSect
);
1570 /***********************************************************************
1571 * WritePrivateProfileStringA (KERNEL32.@)
1573 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1574 LPCSTR string
, LPCSTR filename
)
1576 UNICODE_STRING sectionW
, entryW
, stringW
, filenameW
;
1579 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1580 else sectionW
.Buffer
= NULL
;
1581 if (entry
) RtlCreateUnicodeStringFromAsciiz(&entryW
, entry
);
1582 else entryW
.Buffer
= NULL
;
1583 if (string
) RtlCreateUnicodeStringFromAsciiz(&stringW
, string
);
1584 else stringW
.Buffer
= NULL
;
1585 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1586 else filenameW
.Buffer
= NULL
;
1588 ret
= WritePrivateProfileStringW(sectionW
.Buffer
, entryW
.Buffer
,
1589 stringW
.Buffer
, filenameW
.Buffer
);
1590 RtlFreeUnicodeString(§ionW
);
1591 RtlFreeUnicodeString(&entryW
);
1592 RtlFreeUnicodeString(&stringW
);
1593 RtlFreeUnicodeString(&filenameW
);
1597 /***********************************************************************
1598 * WritePrivateProfileSection (KERNEL.416)
1600 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1601 LPCSTR string
, LPCSTR filename
)
1603 return WritePrivateProfileSectionA( section
, string
, filename
);
1606 /***********************************************************************
1607 * WritePrivateProfileSectionW (KERNEL32.@)
1609 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1610 LPCWSTR string
, LPCWSTR filename
)
1615 EnterCriticalSection( &PROFILE_CritSect
);
1617 if (PROFILE_Open( filename
)) {
1618 if (!section
&& !string
)
1619 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1620 else if (!string
) {/* delete the named section*/
1621 ret
= PROFILE_SetString(section
,NULL
,NULL
, FALSE
);
1622 PROFILE_FlushFile();
1624 PROFILE_DeleteAllKeys(section
);
1627 LPWSTR buf
= HeapAlloc( GetProcessHeap(), 0, (strlenW(string
)+1) * sizeof(WCHAR
) );
1628 strcpyW( buf
, string
);
1629 if((p
= strchrW( buf
, '='))) {
1631 ret
= PROFILE_SetString( section
, buf
, p
+1, TRUE
);
1633 HeapFree( GetProcessHeap(), 0, buf
);
1634 string
+= strlenW(string
)+1;
1636 PROFILE_FlushFile();
1640 LeaveCriticalSection( &PROFILE_CritSect
);
1644 /***********************************************************************
1645 * WritePrivateProfileSectionA (KERNEL32.@)
1647 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1648 LPCSTR string
, LPCSTR filename
)
1651 UNICODE_STRING sectionW
, filenameW
;
1660 while(*p
) p
+= strlen(p
) + 1;
1661 lenA
= p
- string
+ 1;
1662 lenW
= MultiByteToWideChar(CP_ACP
, 0, string
, lenA
, NULL
, 0);
1663 if ((stringW
= HeapAlloc(GetProcessHeap(), 0, lenW
* sizeof(WCHAR
))))
1664 MultiByteToWideChar(CP_ACP
, 0, string
, lenA
, stringW
, lenW
);
1666 else stringW
= NULL
;
1667 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1668 else sectionW
.Buffer
= NULL
;
1669 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1670 else filenameW
.Buffer
= NULL
;
1672 ret
= WritePrivateProfileSectionW(sectionW
.Buffer
, stringW
, filenameW
.Buffer
);
1674 HeapFree(GetProcessHeap(), 0, stringW
);
1675 RtlFreeUnicodeString(§ionW
);
1676 RtlFreeUnicodeString(&filenameW
);
1680 /***********************************************************************
1681 * WriteProfileSection (KERNEL.417)
1683 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1685 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1688 /***********************************************************************
1689 * WriteProfileSectionA (KERNEL32.@)
1691 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1694 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1697 /***********************************************************************
1698 * WriteProfileSectionW (KERNEL32.@)
1700 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1702 return WritePrivateProfileSectionW(section
, keys_n_values
, wininiW
);
1705 /***********************************************************************
1706 * GetPrivateProfileSectionNames (KERNEL.143)
1708 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1711 return GetPrivateProfileSectionNamesA(buffer
,size
,filename
);
1715 /***********************************************************************
1716 * GetProfileSectionNames (KERNEL.142)
1718 WORD WINAPI
GetProfileSectionNames16(LPSTR buffer
, WORD size
)
1721 return GetPrivateProfileSectionNamesA(buffer
,size
,"win.ini");
1725 /***********************************************************************
1726 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1728 * Returns the section names contained in the specified file.
1729 * FIXME: Where do we find this file when the path is relative?
1730 * The section names are returned as a list of strings with an extra
1731 * '\0' to mark the end of the list. Except for that the behavior
1732 * depends on the Windows version.
1735 * - if the buffer is 0 or 1 character long then it is as if it was of
1737 * - otherwise, if the buffer is to small only the section names that fit
1739 * - note that this means if the buffer was to small to return even just
1740 * the first section name then a single '\0' will be returned.
1741 * - the return value is the number of characters written in the buffer,
1742 * except if the buffer was too smal in which case len-2 is returned
1745 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1746 * '\0' and the return value is 0
1747 * - otherwise if the buffer is too small then the first section name that
1748 * does not fit is truncated so that the string list can be terminated
1749 * correctly (double '\0')
1750 * - the return value is the number of characters written in the buffer
1751 * except for the trailing '\0'. If the buffer is too small, then the
1752 * return value is len-2
1753 * - Win2000 has a bug that triggers when the section names and the
1754 * trailing '\0' fit exactly in the buffer. In that case the trailing
1757 * Wine implements the observed Win2000 behavior (except for the bug).
1759 * Note that when the buffer is big enough then the return value may be any
1760 * value between 1 and len-1 (or len in Win95), including len-2.
1762 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1767 EnterCriticalSection( &PROFILE_CritSect
);
1769 if (PROFILE_Open( filename
))
1770 ret
= PROFILE_GetSectionNames(buffer
, size
);
1772 LeaveCriticalSection( &PROFILE_CritSect
);
1778 /***********************************************************************
1779 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1781 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1784 UNICODE_STRING filenameW
;
1788 bufferW
= buffer
? HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
)) : NULL
;
1789 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1790 else filenameW
.Buffer
= NULL
;
1792 retW
= GetPrivateProfileSectionNamesW(bufferW
, size
, filenameW
.Buffer
);
1795 ret
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, retW
, buffer
, size
, NULL
, NULL
);
1803 RtlFreeUnicodeString(&filenameW
);
1804 if (bufferW
) HeapFree(GetProcessHeap(), 0, bufferW
);
1808 /***********************************************************************
1809 * GetPrivateProfileStruct (KERNEL.407)
1811 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1812 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1814 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1817 /***********************************************************************
1818 * GetPrivateProfileStructW (KERNEL32.@)
1820 * Should match Win95's behaviour pretty much
1822 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1823 LPVOID buf
, UINT len
, LPCWSTR filename
)
1827 EnterCriticalSection( &PROFILE_CritSect
);
1829 if (PROFILE_Open( filename
)) {
1830 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
, FALSE
);
1832 TRACE("value (at %p): %s\n", k
->value
, debugstr_w(k
->value
));
1833 if (((strlenW(k
->value
) - 2) / 2) == len
)
1840 end
= k
->value
+ strlenW(k
->value
); /* -> '\0' */
1841 /* check for invalid chars in ASCII coded hex string */
1842 for (p
=k
->value
; p
< end
; p
++)
1846 WARN("invalid char '%x' in file %s->[%s]->%s !\n",
1847 *p
, debugstr_w(filename
), debugstr_w(section
), debugstr_w(key
));
1854 BOOL highnibble
= TRUE
;
1856 LPBYTE binbuf
= (LPBYTE
)buf
;
1858 end
-= 2; /* don't include checksum in output data */
1859 /* translate ASCII hex format into binary data */
1860 for (p
=k
->value
; p
< end
; p
++)
1864 (c
- 'A' + 10) : (c
- '0');
1871 *binbuf
++ = b
; /* feed binary data into output */
1872 chksum
+= b
; /* calculate checksum */
1874 highnibble
^= 1; /* toggle */
1876 /* retrieve stored checksum value */
1878 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1880 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1881 if (b
== (chksum
& 0xff)) /* checksums match ? */
1887 LeaveCriticalSection( &PROFILE_CritSect
);
1892 /***********************************************************************
1893 * GetPrivateProfileStructA (KERNEL32.@)
1895 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1896 LPVOID buffer
, UINT len
, LPCSTR filename
)
1898 UNICODE_STRING sectionW
, keyW
, filenameW
;
1901 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1902 else sectionW
.Buffer
= NULL
;
1903 if (key
) RtlCreateUnicodeStringFromAsciiz(&keyW
, key
);
1904 else keyW
.Buffer
= NULL
;
1905 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1906 else filenameW
.Buffer
= NULL
;
1908 ret
= GetPrivateProfileStructW(sectionW
.Buffer
, keyW
.Buffer
, buffer
, len
,
1910 /* Do not translate binary data. */
1912 RtlFreeUnicodeString(§ionW
);
1913 RtlFreeUnicodeString(&keyW
);
1914 RtlFreeUnicodeString(&filenameW
);
1920 /***********************************************************************
1921 * WritePrivateProfileStruct (KERNEL.406)
1923 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1924 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1926 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1929 /***********************************************************************
1930 * WritePrivateProfileStructW (KERNEL32.@)
1932 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1933 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1937 LPWSTR outstring
, p
;
1940 if (!section
&& !key
&& !buf
) /* flush the cache */
1941 return WritePrivateProfileStringW( NULL
, NULL
, NULL
, filename
);
1943 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1944 outstring
= HeapAlloc( GetProcessHeap(), 0, (bufsize
*2 + 2 + 1) * sizeof(WCHAR
) );
1946 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1947 *p
++ = hex
[*binbuf
>> 4];
1948 *p
++ = hex
[*binbuf
& 0xf];
1951 /* checksum is sum & 0xff */
1952 *p
++ = hex
[(sum
& 0xf0) >> 4];
1953 *p
++ = hex
[sum
& 0xf];
1956 EnterCriticalSection( &PROFILE_CritSect
);
1958 if (PROFILE_Open( filename
)) {
1959 ret
= PROFILE_SetString( section
, key
, outstring
, FALSE
);
1960 PROFILE_FlushFile();
1963 LeaveCriticalSection( &PROFILE_CritSect
);
1965 HeapFree( GetProcessHeap(), 0, outstring
);
1970 /***********************************************************************
1971 * WritePrivateProfileStructA (KERNEL32.@)
1973 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1974 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1976 UNICODE_STRING sectionW
, keyW
, filenameW
;
1979 if (section
) RtlCreateUnicodeStringFromAsciiz(§ionW
, section
);
1980 else sectionW
.Buffer
= NULL
;
1981 if (key
) RtlCreateUnicodeStringFromAsciiz(&keyW
, key
);
1982 else keyW
.Buffer
= NULL
;
1983 if (filename
) RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
1984 else filenameW
.Buffer
= NULL
;
1986 /* Do not translate binary data. */
1987 ret
= WritePrivateProfileStructW(sectionW
.Buffer
, keyW
.Buffer
, buf
, bufsize
,
1990 RtlFreeUnicodeString(§ionW
);
1991 RtlFreeUnicodeString(&keyW
);
1992 RtlFreeUnicodeString(&filenameW
);
1997 /***********************************************************************
1998 * WriteOutProfiles (KERNEL.315)
2000 void WINAPI
WriteOutProfiles16(void)
2002 EnterCriticalSection( &PROFILE_CritSect
);
2003 PROFILE_FlushFile();
2004 LeaveCriticalSection( &PROFILE_CritSect
);
2007 /***********************************************************************
2008 * CloseProfileUserMapping (KERNEL32.@)
2010 BOOL WINAPI
CloseProfileUserMapping(void) {
2011 FIXME("(), stub!\n");
2012 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);