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>
43 #include "wine/winbase16.h"
45 #include "wine/unicode.h"
46 #include "wine/server.h"
47 #include "wine/library.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(profile);
52 typedef struct tagPROFILEKEY
55 struct tagPROFILEKEY *next;
59 typedef struct tagPROFILESECTION
61 struct tagPROFILEKEY *key;
62 struct tagPROFILESECTION *next;
70 PROFILESECTION *section;
78 #define N_CACHED_PROFILES 10
80 /* Cached profile files */
81 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
83 #define CurProfile (MRUProfile[0])
85 #define PROFILE_MAX_LINE_LEN 1024
87 /* Check for comments in profile */
88 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
90 static const WCHAR emptystringW[] = {0};
91 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
93 static CRITICAL_SECTION PROFILE_CritSect;
94 static CRITICAL_SECTION_DEBUG critsect_debug =
96 0, 0, &PROFILE_CritSect,
97 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
98 0, 0, { 0, (DWORD)(__FILE__ ": PROFILE_CritSect") }
100 static CRITICAL_SECTION PROFILE_CritSect = { &critsect_debug, -1, 0, 0, 0, 0 };
102 static const char hex[16] = "0123456789ABCDEF";
104 /***********************************************************************
107 * Copy the content of an entry into a buffer, removing quotes, and possibly
108 * translating environment variables.
110 static void PROFILE_CopyEntry( LPWSTR buffer, LPCWSTR value, int len,
117 if (strip_quote && ((*value == '\'') || (*value == '\"')))
119 if (value[1] && (value[strlenW(value)-1] == *value)) quote = *value++;
122 lstrcpynW( buffer, value, len );
123 if (quote && (len >= strlenW(value))) buffer[strlenW(buffer)-1] = '\0';
127 /***********************************************************************
130 * Save a profile tree to a file.
132 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
135 char buffer[PROFILE_MAX_LINE_LEN];
137 for ( ; section; section = section->next)
139 if (section->name[0])
141 WideCharToMultiByte(CP_ACP, 0, section->name, -1, buffer, sizeof(buffer), NULL, NULL);
142 fprintf( file, "\r\n[%s]\r\n", buffer );
144 for (key = section->key; key; key = key->next)
146 WideCharToMultiByte(CP_ACP, 0, key->name, -1, buffer, sizeof(buffer), NULL, NULL);
147 fprintf( file, "%s", buffer );
150 WideCharToMultiByte(CP_ACP, 0, key->value, -1, buffer, sizeof(buffer), NULL, NULL);
151 fprintf( file, "=%s", buffer );
153 fprintf( file, "\r\n" );
159 /***********************************************************************
162 * Free a profile tree.
164 static void PROFILE_Free( PROFILESECTION *section )
166 PROFILESECTION *next_section;
167 PROFILEKEY *key, *next_key;
169 for ( ; section; section = next_section)
171 for (key = section->key; key; key = next_key)
173 next_key = key->next;
174 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
175 HeapFree( GetProcessHeap(), 0, key );
177 next_section = section->next;
178 HeapFree( GetProcessHeap(), 0, section );
182 static inline int PROFILE_isspace(char c)
184 if (isspace(c)) return 1;
185 if (c=='\r' || c==0x1a) return 1;
186 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
191 /***********************************************************************
194 * Load a profile tree from a file.
196 static PROFILESECTION *PROFILE_Load( FILE *file )
198 char buffer[PROFILE_MAX_LINE_LEN];
201 PROFILESECTION *section, *first_section;
202 PROFILESECTION **next_section;
203 PROFILEKEY *key, *prev_key, **next_key;
205 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
206 if(first_section == NULL) return NULL;
207 first_section->name[0] = 0;
208 first_section->key = NULL;
209 first_section->next = NULL;
210 next_section = &first_section->next;
211 next_key = &first_section->key;
214 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
218 while (*p && PROFILE_isspace(*p)) p++;
219 if (*p == '[') /* section start */
221 if (!(p2 = strrchr( p, ']' )))
223 WARN("Invalid section header at line %d: '%s'\n",
231 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) )))
233 MultiByteToWideChar(CP_ACP, 0, p, -1, section->name, len + 1);
235 section->next = NULL;
236 *next_section = section;
237 next_section = §ion->next;
238 next_key = §ion->key;
241 TRACE("New section: %s\n", debugstr_w(section->name));
248 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
250 if ((p2 = strchr( p, '=' )) != NULL)
253 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
255 while (*p2 && PROFILE_isspace(*p2)) p2++;
258 if(*p || !prev_key || *prev_key->name)
261 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + len * sizeof(WCHAR) ))) break;
262 MultiByteToWideChar(CP_ACP, 0, p, -1, key->name, len + 1);
265 len = strlen(p2) + 1;
266 key->value = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
267 MultiByteToWideChar(CP_ACP, 0, p2, -1, key->value, len);
269 else key->value = NULL;
273 next_key = &key->next;
276 TRACE("New key: name=%s, value=%s\n",
277 debugstr_w(key->name), key->value ? debugstr_w(key->value) : "(none)");
280 return first_section;
284 /***********************************************************************
285 * PROFILE_DeleteSection
287 * Delete a section from a profile tree.
289 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCWSTR name )
293 if ((*section)->name[0] && !strcmpiW( (*section)->name, name ))
295 PROFILESECTION *to_del = *section;
296 *section = to_del->next;
298 PROFILE_Free( to_del );
301 section = &(*section)->next;
307 /***********************************************************************
310 * Delete a key from a profile tree.
312 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
313 LPCWSTR section_name, LPCWSTR key_name )
317 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
319 PROFILEKEY **key = &(*section)->key;
322 if (!strcmpiW( (*key)->name, key_name ))
324 PROFILEKEY *to_del = *key;
326 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
327 HeapFree( GetProcessHeap(), 0, to_del );
333 section = &(*section)->next;
339 /***********************************************************************
340 * PROFILE_DeleteAllKeys
342 * Delete all keys from a profile tree.
344 void PROFILE_DeleteAllKeys( LPCWSTR section_name)
346 PROFILESECTION **section= &CurProfile->section;
349 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
351 PROFILEKEY **key = &(*section)->key;
354 PROFILEKEY *to_del = *key;
356 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
357 HeapFree( GetProcessHeap(), 0, to_del );
358 CurProfile->changed =TRUE;
361 section = &(*section)->next;
366 /***********************************************************************
369 * Find a key in a profile tree, optionally creating it.
371 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, LPCWSTR section_name,
372 LPCWSTR key_name, BOOL create, BOOL create_always )
377 while (PROFILE_isspace(*section_name)) section_name++;
378 p = section_name + strlenW(section_name) - 1;
379 while ((p > section_name) && PROFILE_isspace(*p)) p--;
380 seclen = p - section_name + 1;
382 while (PROFILE_isspace(*key_name)) key_name++;
383 p = key_name + strlenW(key_name) - 1;
384 while ((p > key_name) && PROFILE_isspace(*p)) p--;
385 keylen = p - key_name + 1;
389 if ( ((*section)->name[0])
390 && (!(strncmpiW( (*section)->name, section_name, seclen )))
391 && (((*section)->name)[seclen] == '\0') )
393 PROFILEKEY **key = &(*section)->key;
397 /* If create_always is FALSE then we check if the keyname
398 * already exists. Otherwise we add it regardless of its
399 * existence, to allow keys to be added more than once in
404 if ( (!(strncmpiW( (*key)->name, key_name, keylen )))
405 && (((*key)->name)[keylen] == '\0') )
410 if (!create) return NULL;
411 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
413 strcpyW( (*key)->name, key_name );
414 (*key)->value = NULL;
418 section = &(*section)->next;
420 if (!create) return NULL;
421 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlenW(section_name) * sizeof(WCHAR) );
422 if(*section == NULL) return NULL;
423 strcpyW( (*section)->name, section_name );
424 (*section)->next = NULL;
425 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
426 sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
428 HeapFree(GetProcessHeap(), 0, *section);
431 strcpyW( (*section)->key->name, key_name );
432 (*section)->key->value = NULL;
433 (*section)->key->next = NULL;
434 return (*section)->key;
438 /***********************************************************************
441 * Flush the current profile to disk if changed.
443 static BOOL PROFILE_FlushFile(void)
445 char *p, buffer[MAX_PATHNAME_LEN];
446 const char *unix_name;
452 WARN("No current profile!\n");
456 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
457 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
459 WCHAR *name, *name_lwr;
460 /* Try to create it in $HOME/.wine */
461 /* FIXME: this will need a more general solution */
462 strcpy( buffer, wine_get_config_dir() );
463 p = buffer + strlen(buffer);
465 *p = 0; /* make strlen() below happy */
466 name = strrchrW( CurProfile->dos_name, '\\' ) + 1;
468 /* create a lower cased version of the name */
469 name_lwr = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
470 strcpyW(name_lwr, name);
472 WideCharToMultiByte(CP_UNIXCP, 0, name_lwr, -1,
473 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
474 HeapFree(GetProcessHeap(), 0, name_lwr);
476 file = fopen( buffer, "w" );
482 WARN("could not save profile file %s\n", debugstr_w(CurProfile->dos_name));
486 TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile->dos_name), unix_name );
487 PROFILE_Save( file, CurProfile->section );
489 CurProfile->changed = FALSE;
490 if(!stat(unix_name,&buf))
491 CurProfile->mtime=buf.st_mtime;
496 /***********************************************************************
497 * PROFILE_ReleaseFile
499 * Flush the current profile to disk and remove it from the cache.
501 static void PROFILE_ReleaseFile(void)
504 PROFILE_Free( CurProfile->section );
505 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
506 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
507 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
508 CurProfile->changed = FALSE;
509 CurProfile->section = NULL;
510 CurProfile->dos_name = NULL;
511 CurProfile->unix_name = NULL;
512 CurProfile->filename = NULL;
513 CurProfile->mtime = 0;
517 /***********************************************************************
520 * Open a profile file, checking the cached file first.
522 static BOOL PROFILE_Open( LPCWSTR filename )
524 DOS_FULL_NAME full_name;
525 char buffer[MAX_PATHNAME_LEN];
527 WCHAR *name, *name_lwr;
532 PROFILE *tempProfile;
534 /* First time around */
537 for(i=0;i<N_CACHED_PROFILES;i++)
539 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
540 if(MRUProfile[i] == NULL) break;
541 MRUProfile[i]->changed=FALSE;
542 MRUProfile[i]->section=NULL;
543 MRUProfile[i]->dos_name=NULL;
544 MRUProfile[i]->unix_name=NULL;
545 MRUProfile[i]->filename=NULL;
546 MRUProfile[i]->mtime=0;
549 /* Check for a match */
551 if (strchrW( filename, '/' ) || strchrW( filename, '\\' ) ||
552 strchrW( filename, ':' ))
554 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
558 static const WCHAR bkslashW[] = {'\\',0};
559 WCHAR windirW[MAX_PATH];
561 GetWindowsDirectoryW( windirW, MAX_PATH );
562 strcatW( windirW, bkslashW );
563 strcatW( windirW, filename );
564 if (!DOSFS_GetFullName( windirW, FALSE, &full_name )) return FALSE;
567 for(i=0;i<N_CACHED_PROFILES;i++)
569 if ((MRUProfile[i]->filename && !strcmpW( filename, MRUProfile[i]->filename )) ||
570 (MRUProfile[i]->dos_name && !strcmpW( full_name.short_name, MRUProfile[i]->dos_name )))
575 tempProfile=MRUProfile[i];
577 MRUProfile[j]=MRUProfile[j-1];
578 CurProfile=tempProfile;
580 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
581 TRACE("(%s): already opened (mru=%d)\n",
582 debugstr_w(filename), i );
584 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
585 debugstr_w(filename), i );
590 /* Flush the old current profile */
593 /* Make the oldest profile the current one only in order to get rid of it */
594 if(i==N_CACHED_PROFILES)
596 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
597 for(i=N_CACHED_PROFILES-1;i>0;i--)
598 MRUProfile[i]=MRUProfile[i-1];
599 CurProfile=tempProfile;
601 if(CurProfile->filename) PROFILE_ReleaseFile();
603 /* OK, now that CurProfile is definitely free we assign it our new file */
604 newdos_name = HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name.short_name)+1) * sizeof(WCHAR) );
605 strcpyW( newdos_name, full_name.short_name );
606 CurProfile->dos_name = newdos_name;
607 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, (strlenW(filename)+1) * sizeof(WCHAR) );
608 strcpyW( CurProfile->filename, filename );
610 /* Try to open the profile file, first in $HOME/.wine */
612 /* FIXME: this will need a more general solution */
613 strcpy( buffer, wine_get_config_dir() );
614 p = buffer + strlen(buffer);
616 *p = 0; /* make strlen() below happy */
617 name = strrchrW( newdos_name, '\\' ) + 1;
619 /* create a lower cased version of the name */
620 name_lwr = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
621 strcpyW(name_lwr, name);
623 WideCharToMultiByte(CP_UNIXCP, 0, name_lwr, -1,
624 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
625 HeapFree(GetProcessHeap(), 0, name_lwr);
627 if ((file = fopen( buffer, "r" )))
629 TRACE("(%s): found it in %s\n", debugstr_w(filename), buffer );
630 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
631 strcpy( CurProfile->unix_name, buffer );
635 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
636 strcpy( CurProfile->unix_name, full_name.long_name );
637 if ((file = fopen( full_name.long_name, "r" )))
638 TRACE("(%s): found it in %s\n",
639 debugstr_w(filename), full_name.long_name );
644 CurProfile->section = PROFILE_Load( file );
646 if(!stat(CurProfile->unix_name,&buf))
647 CurProfile->mtime=buf.st_mtime;
651 /* Does not exist yet, we will create it in PROFILE_FlushFile */
652 WARN("profile file %s not found\n", debugstr_w(newdos_name) );
658 /***********************************************************************
661 * Returns all keys of a section.
662 * If return_values is TRUE, also include the corresponding values.
664 static INT PROFILE_GetSection( PROFILESECTION *section, LPCWSTR section_name,
665 LPWSTR buffer, UINT len, BOOL return_values )
669 if(!buffer) return 0;
671 TRACE("%s,%p,%u\n", debugstr_w(section_name), buffer, len);
675 if (section->name[0] && !strcmpiW( section->name, section_name ))
678 for (key = section->key; key; key = key->next)
681 if (!*key->name) continue; /* Skip empty lines */
682 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
683 PROFILE_CopyEntry( buffer, key->name, len - 1, 0 );
684 len -= strlenW(buffer) + 1;
685 buffer += strlenW(buffer) + 1;
688 if (return_values && key->value) {
690 PROFILE_CopyEntry ( buffer, key->value, len - 1, 0 );
691 len -= strlenW(buffer) + 1;
692 buffer += strlenW(buffer) + 1;
697 /*If either lpszSection or lpszKey is NULL and the supplied
698 destination buffer is too small to hold all the strings,
699 the last string is truncated and followed by two null characters.
700 In this case, the return value is equal to cchReturnBuffer
708 section = section->next;
710 buffer[0] = buffer[1] = '\0';
714 /* See GetPrivateProfileSectionNamesA for documentation */
715 static INT PROFILE_GetSectionNames( LPWSTR buffer, UINT len )
719 PROFILESECTION *section;
730 section = CurProfile->section;
731 while ((section!=NULL)) {
732 if (section->name[0]) {
733 l = strlenW(section->name)+1;
736 strncpyW(buf, section->name, f-1);
743 strcpyW(buf, section->name);
747 section = section->next;
754 /***********************************************************************
757 * Get a profile string.
759 * Tests with GetPrivateProfileString16, W95a,
760 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
761 * section key_name def_val res buffer
762 * "set1" "1" "x" 43 [data]
763 * "set1" "1 " "x" 43 [data] (!)
764 * "set1" " 1 "' "x" 43 [data] (!)
765 * "set1" "" "x" 1 "x"
766 * "set1" "" "x " 1 "x" (!)
767 * "set1" "" " x " 3 " x" (!)
768 * "set1" NULL "x" 6 "1\02\03\0\0"
769 * "set1" "" "x" 1 "x"
770 * NULL "1" "x" 0 "" (!)
776 static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name,
777 LPCWSTR def_val, LPWSTR buffer, UINT len )
779 PROFILEKEY *key = NULL;
780 static const WCHAR empty_strW[] = { 0 };
782 if(!buffer) return 0;
784 if (!def_val) def_val = empty_strW;
789 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
792 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
793 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
795 TRACE("(%s,%s,%s): returning %s\n",
796 debugstr_w(section), debugstr_w(key_name),
797 debugstr_w(def_val), debugstr_w(buffer) );
798 return strlenW( buffer );
800 /* no "else" here ! */
801 if (section && section[0])
803 INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE);
804 if (!buffer[0]) /* no luck -> def_val */
806 PROFILE_CopyEntry(buffer, def_val, len, TRUE);
807 ret = strlenW(buffer);
816 /***********************************************************************
819 * Set a profile string.
821 static BOOL PROFILE_SetString( LPCWSTR section_name, LPCWSTR key_name,
822 LPCWSTR value, BOOL create_always )
824 if (!key_name) /* Delete a whole section */
826 TRACE("(%s)\n", debugstr_w(section_name));
827 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
829 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
830 this is not an error on application's level.*/
832 else if (!value) /* Delete a key */
834 TRACE("(%s,%s)\n", debugstr_w(section_name), debugstr_w(key_name) );
835 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
836 section_name, key_name );
837 return TRUE; /* same error handling as above */
839 else /* Set the key value */
841 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
842 key_name, TRUE, create_always );
843 TRACE("(%s,%s,%s):\n",
844 debugstr_w(section_name), debugstr_w(key_name), debugstr_w(value) );
845 if (!key) return FALSE;
848 /* strip the leading spaces. We can safely strip \n\r and
849 * friends too, they should not happen here anyway. */
850 while (PROFILE_isspace(*value)) value++;
852 if (!strcmpW( key->value, value ))
854 TRACE(" no change needed\n" );
855 return TRUE; /* No change needed */
857 TRACE(" replacing %s\n", debugstr_w(key->value) );
858 HeapFree( GetProcessHeap(), 0, key->value );
860 else TRACE(" creating key\n" );
861 key->value = HeapAlloc( GetProcessHeap(), 0, (strlenW(value)+1) * sizeof(WCHAR) );
862 strcpyW( key->value, value );
863 CurProfile->changed = TRUE;
869 /********************* API functions **********************************/
871 /***********************************************************************
872 * GetProfileInt (KERNEL.57)
874 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
876 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
880 /***********************************************************************
881 * GetProfileIntA (KERNEL32.@)
883 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
885 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
888 /***********************************************************************
889 * GetProfileIntW (KERNEL32.@)
891 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
893 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
897 * if allow_section_name_copy is TRUE, allow the copying :
898 * - of Section names if 'section' is NULL
899 * - of Keys in a Section if 'entry' is NULL
900 * (see MSDN doc for GetPrivateProfileString)
902 static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry,
903 LPCWSTR def_val, LPWSTR buffer,
904 UINT len, LPCWSTR filename,
905 BOOL allow_section_name_copy )
908 LPWSTR pDefVal = NULL;
913 TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section), debugstr_w(entry),
914 debugstr_w(def_val), buffer, len, debugstr_w(filename));
916 /* strip any trailing ' ' of def_val. */
919 LPCWSTR p = &def_val[strlenW(def_val)]; /* even "" works ! */
927 if (*p == ' ') /* ouch, contained trailing ' ' */
929 int len = (int)(p - def_val);
930 pDefVal = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
931 strncpyW(pDefVal, def_val, len);
936 pDefVal = (LPWSTR)def_val;
938 RtlEnterCriticalSection( &PROFILE_CritSect );
940 if (PROFILE_Open( filename )) {
941 if ((allow_section_name_copy) && (section == NULL))
942 ret = PROFILE_GetSectionNames(buffer, len);
944 /* PROFILE_GetString already handles the 'entry == NULL' case */
945 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
947 lstrcpynW( buffer, pDefVal, len );
948 ret = strlenW( buffer );
951 RtlLeaveCriticalSection( &PROFILE_CritSect );
953 if (pDefVal != def_val) /* allocated */
954 HeapFree(GetProcessHeap(), 0, pDefVal);
956 TRACE("returning %s, %d\n", debugstr_w(buffer), ret);
961 /***********************************************************************
962 * GetPrivateProfileString (KERNEL.128)
964 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
965 LPCSTR def_val, LPSTR buffer,
966 UINT16 len, LPCSTR filename )
968 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
972 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
973 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
974 else sectionW.Buffer = NULL;
975 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
976 else entryW.Buffer = NULL;
977 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
978 else def_valW.Buffer = NULL;
979 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
980 else filenameW.Buffer = NULL;
982 retW = PROFILE_GetPrivateProfileString( sectionW.Buffer, entryW.Buffer,
983 def_valW.Buffer, bufferW, len,
984 filenameW.Buffer, FALSE );
987 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
994 ret--; /* strip terminating 0 */
997 RtlFreeUnicodeString(§ionW);
998 RtlFreeUnicodeString(&entryW);
999 RtlFreeUnicodeString(&def_valW);
1000 RtlFreeUnicodeString(&filenameW);
1001 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1005 /***********************************************************************
1006 * GetPrivateProfileStringA (KERNEL32.@)
1008 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1009 LPCSTR def_val, LPSTR buffer,
1010 UINT len, LPCSTR filename )
1012 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1016 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1017 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1018 else sectionW.Buffer = NULL;
1019 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1020 else entryW.Buffer = NULL;
1021 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1022 else def_valW.Buffer = NULL;
1023 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1024 else filenameW.Buffer = NULL;
1026 retW = GetPrivateProfileStringW( sectionW.Buffer, entryW.Buffer,
1027 def_valW.Buffer, bufferW, len,
1031 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1038 ret--; /* strip terminating 0 */
1041 RtlFreeUnicodeString(§ionW);
1042 RtlFreeUnicodeString(&entryW);
1043 RtlFreeUnicodeString(&def_valW);
1044 RtlFreeUnicodeString(&filenameW);
1045 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1049 /***********************************************************************
1050 * GetPrivateProfileStringW (KERNEL32.@)
1052 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1053 LPCWSTR def_val, LPWSTR buffer,
1054 UINT len, LPCWSTR filename )
1056 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1057 buffer, len, filename, TRUE );
1060 /***********************************************************************
1061 * GetProfileString (KERNEL.58)
1063 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1064 LPSTR buffer, UINT16 len )
1066 return GetPrivateProfileString16( section, entry, def_val,
1067 buffer, len, "win.ini" );
1070 /***********************************************************************
1071 * GetProfileStringA (KERNEL32.@)
1073 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1074 LPSTR buffer, UINT len )
1076 return GetPrivateProfileStringA( section, entry, def_val,
1077 buffer, len, "win.ini" );
1080 /***********************************************************************
1081 * GetProfileStringW (KERNEL32.@)
1083 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1084 LPCWSTR def_val, LPWSTR buffer, UINT len )
1086 return GetPrivateProfileStringW( section, entry, def_val,
1087 buffer, len, wininiW );
1090 /***********************************************************************
1091 * WriteProfileString (KERNEL.59)
1093 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1096 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1099 /***********************************************************************
1100 * WriteProfileStringA (KERNEL32.@)
1102 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1105 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1108 /***********************************************************************
1109 * WriteProfileStringW (KERNEL32.@)
1111 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1114 return WritePrivateProfileStringW( section, entry, string, wininiW );
1118 /***********************************************************************
1119 * GetPrivateProfileInt (KERNEL.127)
1121 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1122 INT16 def_val, LPCSTR filename )
1124 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1125 * here, but Win98SE doesn't care about this at all, so I deleted it.
1126 * AFAIR versions prior to Win9x had these limits, though. */
1127 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
1130 /***********************************************************************
1131 * GetPrivateProfileIntW (KERNEL32.@)
1133 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1134 INT def_val, LPCWSTR filename )
1137 UNICODE_STRING bufferW;
1141 if (!(len = GetPrivateProfileStringW( section, entry, emptystringW,
1142 buffer, sizeof(buffer)/sizeof(WCHAR),
1146 if (len+1 == sizeof(buffer)/sizeof(WCHAR)) FIXME("result may be wrong!\n");
1148 /* FIXME: if entry can be found but it's empty, then Win16 is
1149 * supposed to return 0 instead of def_val ! Difficult/problematic
1150 * to implement (every other failure also returns zero buffer),
1151 * thus wait until testing framework avail for making sure nothing
1152 * else gets broken that way. */
1153 if (!buffer[0]) return (UINT)def_val;
1155 RtlInitUnicodeString( &bufferW, buffer );
1156 RtlUnicodeStringToInteger( &bufferW, 10, &result);
1160 /***********************************************************************
1161 * GetPrivateProfileIntA (KERNEL32.@)
1163 * FIXME: rewrite using unicode
1165 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1166 INT def_val, LPCSTR filename )
1168 UNICODE_STRING entryW, filenameW, sectionW;
1170 if(entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1171 else entryW.Buffer = NULL;
1172 if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1173 else filenameW.Buffer = NULL;
1174 if(section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1175 else sectionW.Buffer = NULL;
1176 res = GetPrivateProfileIntW(sectionW.Buffer, entryW.Buffer, def_val,
1178 RtlFreeUnicodeString(§ionW);
1179 RtlFreeUnicodeString(&filenameW);
1180 RtlFreeUnicodeString(&entryW);
1184 /***********************************************************************
1185 * GetPrivateProfileSection (KERNEL.418)
1187 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1188 UINT16 len, LPCSTR filename )
1190 return GetPrivateProfileSectionA( section, buffer, len, filename );
1193 /***********************************************************************
1194 * GetPrivateProfileSectionW (KERNEL32.@)
1196 INT WINAPI GetPrivateProfileSectionW( LPCWSTR section, LPWSTR buffer,
1197 DWORD len, LPCWSTR filename )
1201 RtlEnterCriticalSection( &PROFILE_CritSect );
1203 if (PROFILE_Open( filename ))
1204 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, TRUE);
1206 RtlLeaveCriticalSection( &PROFILE_CritSect );
1211 /***********************************************************************
1212 * GetPrivateProfileSectionA (KERNEL32.@)
1214 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1215 DWORD len, LPCSTR filename )
1217 UNICODE_STRING sectionW, filenameW;
1221 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1222 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1223 else sectionW.Buffer = NULL;
1224 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1225 else filenameW.Buffer = NULL;
1227 retW = GetPrivateProfileSectionW(sectionW.Buffer, bufferW, len, filenameW.Buffer);
1230 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 2, buffer, len, NULL, NULL);
1246 RtlFreeUnicodeString(§ionW);
1247 RtlFreeUnicodeString(&filenameW);
1248 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1252 /***********************************************************************
1253 * GetProfileSection (KERNEL.419)
1255 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1257 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1260 /***********************************************************************
1261 * GetProfileSectionA (KERNEL32.@)
1263 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1265 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1268 /***********************************************************************
1269 * GetProfileSectionW (KERNEL32.@)
1271 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1273 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1277 /***********************************************************************
1278 * WritePrivateProfileString (KERNEL.129)
1280 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1281 LPCSTR string, LPCSTR filename )
1283 return WritePrivateProfileStringA(section,entry,string,filename);
1286 /***********************************************************************
1287 * WritePrivateProfileStringW (KERNEL32.@)
1289 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1290 LPCWSTR string, LPCWSTR filename )
1294 RtlEnterCriticalSection( &PROFILE_CritSect );
1296 if (PROFILE_Open( filename ))
1298 if (!section && !entry && !string) /* documented "file flush" case */
1300 PROFILE_FlushFile();
1301 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1305 FIXME("(NULL?,%s,%s,%s)?\n",
1306 debugstr_w(entry), debugstr_w(string), debugstr_w(filename));
1308 ret = PROFILE_SetString( section, entry, string, FALSE);
1309 PROFILE_FlushFile();
1314 RtlLeaveCriticalSection( &PROFILE_CritSect );
1318 /***********************************************************************
1319 * WritePrivateProfileStringA (KERNEL32.@)
1321 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1322 LPCSTR string, LPCSTR filename )
1324 UNICODE_STRING sectionW, entryW, stringW, filenameW;
1327 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1328 else sectionW.Buffer = NULL;
1329 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1330 else entryW.Buffer = NULL;
1331 if (string) RtlCreateUnicodeStringFromAsciiz(&stringW, string);
1332 else stringW.Buffer = NULL;
1333 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1334 else filenameW.Buffer = NULL;
1336 ret = WritePrivateProfileStringW(sectionW.Buffer, entryW.Buffer,
1337 stringW.Buffer, filenameW.Buffer);
1338 RtlFreeUnicodeString(§ionW);
1339 RtlFreeUnicodeString(&entryW);
1340 RtlFreeUnicodeString(&stringW);
1341 RtlFreeUnicodeString(&filenameW);
1345 /***********************************************************************
1346 * WritePrivateProfileSection (KERNEL.416)
1348 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1349 LPCSTR string, LPCSTR filename )
1351 return WritePrivateProfileSectionA( section, string, filename );
1354 /***********************************************************************
1355 * WritePrivateProfileSectionW (KERNEL32.@)
1357 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1358 LPCWSTR string, LPCWSTR filename )
1363 RtlEnterCriticalSection( &PROFILE_CritSect );
1365 if (PROFILE_Open( filename )) {
1366 if (!section && !string)
1367 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1368 else if (!string) {/* delete the named section*/
1369 ret = PROFILE_SetString(section,NULL,NULL, FALSE);
1370 PROFILE_FlushFile();
1372 PROFILE_DeleteAllKeys(section);
1375 LPWSTR buf = HeapAlloc( GetProcessHeap(), 0, (strlenW(string)+1) * sizeof(WCHAR) );
1376 strcpyW( buf, string );
1377 if((p = strchrW( buf, '='))) {
1379 ret = PROFILE_SetString( section, buf, p+1, TRUE);
1381 HeapFree( GetProcessHeap(), 0, buf );
1382 string += strlenW(string)+1;
1384 PROFILE_FlushFile();
1388 RtlLeaveCriticalSection( &PROFILE_CritSect );
1392 /***********************************************************************
1393 * WritePrivateProfileSectionA (KERNEL32.@)
1395 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1396 LPCSTR string, LPCSTR filename)
1399 UNICODE_STRING sectionW, filenameW;
1408 while(*p) p += strlen(p) + 1;
1409 lenA = p - string + 1;
1410 lenW = MultiByteToWideChar(CP_ACP, 0, string, lenA, NULL, 0);
1411 if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR))))
1412 MultiByteToWideChar(CP_ACP, 0, string, lenA, stringW, lenW);
1414 else stringW = NULL;
1415 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1416 else sectionW.Buffer = NULL;
1417 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1418 else filenameW.Buffer = NULL;
1420 ret = WritePrivateProfileSectionW(sectionW.Buffer, stringW, filenameW.Buffer);
1422 HeapFree(GetProcessHeap(), 0, stringW);
1423 RtlFreeUnicodeString(§ionW);
1424 RtlFreeUnicodeString(&filenameW);
1428 /***********************************************************************
1429 * WriteProfileSection (KERNEL.417)
1431 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1433 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1436 /***********************************************************************
1437 * WriteProfileSectionA (KERNEL32.@)
1439 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1442 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1445 /***********************************************************************
1446 * WriteProfileSectionW (KERNEL32.@)
1448 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1450 return WritePrivateProfileSectionW(section, keys_n_values, wininiW);
1453 /***********************************************************************
1454 * GetPrivateProfileSectionNames (KERNEL.143)
1456 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1459 return GetPrivateProfileSectionNamesA(buffer,size,filename);
1463 /***********************************************************************
1464 * GetProfileSectionNames (KERNEL.142)
1466 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
1469 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
1473 /***********************************************************************
1474 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1476 * Returns the section names contained in the specified file.
1477 * FIXME: Where do we find this file when the path is relative?
1478 * The section names are returned as a list of strings with an extra
1479 * '\0' to mark the end of the list. Except for that the behavior
1480 * depends on the Windows version.
1483 * - if the buffer is 0 or 1 character long then it is as if it was of
1485 * - otherwise, if the buffer is to small only the section names that fit
1487 * - note that this means if the buffer was to small to return even just
1488 * the first section name then a single '\0' will be returned.
1489 * - the return value is the number of characters written in the buffer,
1490 * except if the buffer was too smal in which case len-2 is returned
1493 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1494 * '\0' and the return value is 0
1495 * - otherwise if the buffer is too small then the first section name that
1496 * does not fit is truncated so that the string list can be terminated
1497 * correctly (double '\0')
1498 * - the return value is the number of characters written in the buffer
1499 * except for the trailing '\0'. If the buffer is too small, then the
1500 * return value is len-2
1501 * - Win2000 has a bug that triggers when the section names and the
1502 * trailing '\0' fit exactly in the buffer. In that case the trailing
1505 * Wine implements the observed Win2000 behavior (except for the bug).
1507 * Note that when the buffer is big enough then the return value may be any
1508 * value between 1 and len-1 (or len in Win95), including len-2.
1510 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1515 RtlEnterCriticalSection( &PROFILE_CritSect );
1517 if (PROFILE_Open( filename ))
1518 ret = PROFILE_GetSectionNames(buffer, size);
1520 RtlLeaveCriticalSection( &PROFILE_CritSect );
1526 /***********************************************************************
1527 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1529 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1532 UNICODE_STRING filenameW;
1536 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)) : NULL;
1537 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1538 else filenameW.Buffer = NULL;
1540 retW = GetPrivateProfileSectionNamesW(bufferW, size, filenameW.Buffer);
1543 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW, buffer, size, NULL, NULL);
1551 RtlFreeUnicodeString(&filenameW);
1552 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1556 /***********************************************************************
1557 * GetPrivateProfileStruct (KERNEL.407)
1559 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1560 LPVOID buf, UINT16 len, LPCSTR filename)
1562 return GetPrivateProfileStructA( section, key, buf, len, filename );
1565 /***********************************************************************
1566 * GetPrivateProfileStructW (KERNEL32.@)
1568 * Should match Win95's behaviour pretty much
1570 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1571 LPVOID buf, UINT len, LPCWSTR filename)
1575 RtlEnterCriticalSection( &PROFILE_CritSect );
1577 if (PROFILE_Open( filename )) {
1578 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
1580 TRACE("value (at %p): %s\n", k->value, debugstr_w(k->value));
1581 if (((strlenW(k->value) - 2) / 2) == len)
1588 end = k->value + strlenW(k->value); /* -> '\0' */
1589 /* check for invalid chars in ASCII coded hex string */
1590 for (p=k->value; p < end; p++)
1594 WARN("invalid char '%x' in file %s->[%s]->%s !\n",
1595 *p, debugstr_w(filename), debugstr_w(section), debugstr_w(key));
1602 BOOL highnibble = TRUE;
1604 LPBYTE binbuf = (LPBYTE)buf;
1606 end -= 2; /* don't include checksum in output data */
1607 /* translate ASCII hex format into binary data */
1608 for (p=k->value; p < end; p++)
1612 (c - 'A' + 10) : (c - '0');
1619 *binbuf++ = b; /* feed binary data into output */
1620 chksum += b; /* calculate checksum */
1622 highnibble ^= 1; /* toggle */
1624 /* retrieve stored checksum value */
1626 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1628 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1629 if (b == (chksum & 0xff)) /* checksums match ? */
1635 RtlLeaveCriticalSection( &PROFILE_CritSect );
1640 /***********************************************************************
1641 * GetPrivateProfileStructA (KERNEL32.@)
1643 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1644 LPVOID buffer, UINT len, LPCSTR filename)
1646 UNICODE_STRING sectionW, keyW, filenameW;
1649 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1650 else sectionW.Buffer = NULL;
1651 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
1652 else keyW.Buffer = NULL;
1653 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1654 else filenameW.Buffer = NULL;
1656 ret = GetPrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buffer, len,
1658 /* Do not translate binary data. */
1660 RtlFreeUnicodeString(§ionW);
1661 RtlFreeUnicodeString(&keyW);
1662 RtlFreeUnicodeString(&filenameW);
1668 /***********************************************************************
1669 * WritePrivateProfileStruct (KERNEL.406)
1671 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1672 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1674 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1677 /***********************************************************************
1678 * WritePrivateProfileStructW (KERNEL32.@)
1680 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1681 LPVOID buf, UINT bufsize, LPCWSTR filename)
1685 LPWSTR outstring, p;
1688 if (!section && !key && !buf) /* flush the cache */
1689 return WritePrivateProfileStringW( NULL, NULL, NULL, filename );
1691 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1692 outstring = HeapAlloc( GetProcessHeap(), 0, (bufsize*2 + 2 + 1) * sizeof(WCHAR) );
1694 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1695 *p++ = hex[*binbuf >> 4];
1696 *p++ = hex[*binbuf & 0xf];
1699 /* checksum is sum & 0xff */
1700 *p++ = hex[(sum & 0xf0) >> 4];
1701 *p++ = hex[sum & 0xf];
1704 RtlEnterCriticalSection( &PROFILE_CritSect );
1706 if (PROFILE_Open( filename )) {
1707 ret = PROFILE_SetString( section, key, outstring, FALSE);
1708 PROFILE_FlushFile();
1711 RtlLeaveCriticalSection( &PROFILE_CritSect );
1713 HeapFree( GetProcessHeap(), 0, outstring );
1718 /***********************************************************************
1719 * WritePrivateProfileStructA (KERNEL32.@)
1721 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1722 LPVOID buf, UINT bufsize, LPCSTR filename)
1724 UNICODE_STRING sectionW, keyW, filenameW;
1727 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
1728 else sectionW.Buffer = NULL;
1729 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
1730 else keyW.Buffer = NULL;
1731 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1732 else filenameW.Buffer = NULL;
1734 /* Do not translate binary data. */
1735 ret = WritePrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buf, bufsize,
1738 RtlFreeUnicodeString(§ionW);
1739 RtlFreeUnicodeString(&keyW);
1740 RtlFreeUnicodeString(&filenameW);
1745 /***********************************************************************
1746 * WriteOutProfiles (KERNEL.315)
1748 void WINAPI WriteOutProfiles16(void)
1750 RtlEnterCriticalSection( &PROFILE_CritSect );
1751 PROFILE_FlushFile();
1752 RtlLeaveCriticalSection( &PROFILE_CritSect );
1755 /***********************************************************************
1756 * CloseProfileUserMapping (KERNEL32.@)
1758 BOOL WINAPI CloseProfileUserMapping(void) {
1759 FIXME("(), stub!\n");
1760 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);