4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
13 #include <sys/types.h>
19 #include "wine/winbase16.h"
27 #include "debugtools.h"
31 DEFAULT_DEBUG_CHANNEL(profile
);
33 typedef struct tagPROFILEKEY
37 struct tagPROFILEKEY
*next
;
40 typedef struct tagPROFILESECTION
43 struct tagPROFILEKEY
*key
;
44 struct tagPROFILESECTION
*next
;
51 PROFILESECTION
*section
;
59 #define N_CACHED_PROFILES 10
61 /* Cached profile files */
62 static PROFILE
*MRUProfile
[N_CACHED_PROFILES
]={NULL
};
64 #define CurProfile (MRUProfile[0])
66 /* wine.ini config file registry root */
67 static HKEY wine_profile_key
;
69 #define PROFILE_MAX_LINE_LEN 1024
71 /* Wine profile name in $HOME directory; must begin with slash */
72 static const char PROFILE_WineIniName
[] = "/.winerc";
74 /* Wine profile: the profile file being used */
75 static char PROFILE_WineIniUsed
[MAX_PATHNAME_LEN
] = "";
77 /* Check for comments in profile */
78 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
80 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
82 static const WCHAR wininiW
[] = { 'w','i','n','.','i','n','i',0 };
84 static CRITICAL_SECTION PROFILE_CritSect
= CRITICAL_SECTION_INIT
;
86 static const char hex
[16] = "0123456789ABCDEF";
88 /***********************************************************************
91 * Copy the content of an entry into a buffer, removing quotes, and possibly
92 * translating environment variables.
94 static void PROFILE_CopyEntry( char *buffer
, const char *value
, int len
,
100 if ((*value
== '\'') || (*value
== '\"'))
102 if (value
[1] && (value
[strlen(value
)-1] == *value
)) quote
= *value
++;
107 lstrcpynA( buffer
, value
, len
);
108 if (quote
&& (len
>= strlen(value
))) buffer
[strlen(buffer
)-1] = '\0';
112 for (p
= value
; (*p
&& (len
> 1)); *buffer
++ = *p
++, len
-- )
114 if ((*p
== '$') && (p
[1] == '{'))
118 const char *p2
= strchr( p
, '}' );
119 if (!p2
) continue; /* ignore it */
120 lstrcpynA(env_val
, p
+ 2, min( sizeof(env_val
), (int)(p2
-p
)-1 ));
121 if ((env_p
= getenv( env_val
)) != NULL
)
123 lstrcpynA( buffer
, env_p
, len
);
124 buffer
+= strlen( buffer
);
125 len
-= strlen( buffer
);
130 if (quote
&& (len
> 1)) buffer
--;
135 /***********************************************************************
138 * Save a profile tree to a file.
140 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
144 for ( ; section
; section
= section
->next
)
146 if (section
->name
) fprintf( file
, "\r\n[%s]\r\n", section
->name
);
147 for (key
= section
->key
; key
; key
= key
->next
)
149 fprintf( file
, "%s", key
->name
);
150 if (key
->value
) fprintf( file
, "=%s", key
->value
);
151 fprintf( file
, "\r\n" );
157 /***********************************************************************
160 * Free a profile tree.
162 static void PROFILE_Free( PROFILESECTION
*section
)
164 PROFILESECTION
*next_section
;
165 PROFILEKEY
*key
, *next_key
;
167 for ( ; section
; section
= next_section
)
169 if (section
->name
) HeapFree( GetProcessHeap(), 0, section
->name
);
170 for (key
= section
->key
; key
; key
= next_key
)
172 next_key
= key
->next
;
173 if (key
->name
) HeapFree( GetProcessHeap(), 0, key
->name
);
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
= NULL
;
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",
230 section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
231 if(section
== NULL
) break;
232 section
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
234 section
->next
= NULL
;
235 *next_section
= section
;
236 next_section
= §ion
->next
;
237 next_key
= §ion
->key
;
240 TRACE("New section: '%s'\n",section
->name
);
247 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
249 if ((p2
= strchr( p
, '=' )) != NULL
)
252 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
254 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
257 if(*p
|| !prev_key
|| *prev_key
->name
)
259 key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) );
260 if(key
== NULL
) break;
261 key
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
262 key
->value
= p2
? HEAP_strdupA( GetProcessHeap(), 0, p2
) : NULL
;
265 next_key
= &key
->next
;
268 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
271 return first_section
;
275 /***********************************************************************
276 * PROFILE_RegistryLoad
278 * Load a profile tree from a file into a registry key.
280 static DWORD
PROFILE_RegistryLoad( HKEY root
, FILE *file
)
284 char buffer
[PROFILE_MAX_LINE_LEN
];
288 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
292 while (*p
&& PROFILE_isspace(*p
)) p
++;
293 if (*p
== '[') /* section start */
295 if (!(p2
= strrchr( p
, ']' )))
297 WARN("Invalid section header at line %d: '%s'\n",
304 if (hkey
) RegCloseKey( hkey
);
305 if ((err
= RegCreateKeyExA( root
, p
, 0, NULL
, REG_OPTION_VOLATILE
,
306 KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))) return err
;
307 TRACE("New section: '%s'\n",p
);
313 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
315 if ((p2
= strchr( p
, '=' )) != NULL
)
318 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
320 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
323 if (*p
&& hkey
&& !IS_ENTRY_COMMENT(p
))
326 if ((err
= RegSetValueExA( hkey
, p
, 0, REG_SZ
, p2
, strlen(p2
)+1 )))
331 TRACE("New key: name='%s', value='%s'\n",p
,p2
);
334 if (hkey
) RegCloseKey( hkey
);
339 /***********************************************************************
340 * PROFILE_DeleteSection
342 * Delete a section from a profile tree.
344 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
348 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, name
))
350 PROFILESECTION
*to_del
= *section
;
351 *section
= to_del
->next
;
353 PROFILE_Free( to_del
);
356 section
= &(*section
)->next
;
362 /***********************************************************************
365 * Delete a key from a profile tree.
367 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
368 LPCSTR section_name
, LPCSTR key_name
)
372 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
374 PROFILEKEY
**key
= &(*section
)->key
;
377 if (!strcasecmp( (*key
)->name
, key_name
))
379 PROFILEKEY
*to_del
= *key
;
381 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
382 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
383 HeapFree( GetProcessHeap(), 0, to_del
);
389 section
= &(*section
)->next
;
395 /***********************************************************************
398 * Find a key in a profile tree, optionally creating it.
400 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
,
401 const char *section_name
,
402 const char *key_name
, int create
)
407 while (PROFILE_isspace(*section_name
)) section_name
++;
408 p
= section_name
+ strlen(section_name
) - 1;
409 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
410 seclen
= p
- section_name
+ 1;
412 while (PROFILE_isspace(*key_name
)) key_name
++;
413 p
= key_name
+ strlen(key_name
) - 1;
414 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
415 keylen
= p
- key_name
+ 1;
419 if ( ((*section
)->name
)
420 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
421 && (((*section
)->name
)[seclen
] == '\0') )
423 PROFILEKEY
**key
= &(*section
)->key
;
426 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
427 && (((*key
)->name
)[keylen
] == '\0') )
431 if (!create
) return NULL
;
432 *key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
433 if(*key
== NULL
) return NULL
;
434 (*key
)->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
435 (*key
)->value
= NULL
;
439 section
= &(*section
)->next
;
441 if (!create
) return NULL
;
442 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) );
443 if(*section
== NULL
) return NULL
;
444 (*section
)->name
= HEAP_strdupA( GetProcessHeap(), 0, section_name
);
445 (*section
)->next
= NULL
;
446 (*section
)->key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
447 if((*section
)->key
== NULL
)
449 HeapFree(GetProcessHeap(), 0, *section
);
452 (*section
)->key
->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
453 (*section
)->key
->value
= NULL
;
454 (*section
)->key
->next
= NULL
;
455 return (*section
)->key
;
459 /***********************************************************************
462 * Flush the current profile to disk if changed.
464 static BOOL
PROFILE_FlushFile(void)
466 char *p
, buffer
[MAX_PATHNAME_LEN
];
467 const char *unix_name
;
473 WARN("No current profile!\n");
477 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
478 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
480 /* Try to create it in $HOME/.wine */
481 /* FIXME: this will need a more general solution */
482 strcpy( buffer
, get_config_dir() );
483 p
= buffer
+ strlen(buffer
);
485 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
487 file
= fopen( buffer
, "w" );
493 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
497 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
498 PROFILE_Save( file
, CurProfile
->section
);
500 CurProfile
->changed
= FALSE
;
501 if(!stat(unix_name
,&buf
))
502 CurProfile
->mtime
=buf
.st_mtime
;
507 /***********************************************************************
508 * PROFILE_ReleaseFile
510 * Flush the current profile to disk and remove it from the cache.
512 static void PROFILE_ReleaseFile(void)
515 PROFILE_Free( CurProfile
->section
);
516 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
517 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
518 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
519 CurProfile
->changed
= FALSE
;
520 CurProfile
->section
= NULL
;
521 CurProfile
->dos_name
= NULL
;
522 CurProfile
->unix_name
= NULL
;
523 CurProfile
->filename
= NULL
;
524 CurProfile
->mtime
= 0;
528 /***********************************************************************
531 * Open a profile file, checking the cached file first.
533 static BOOL
PROFILE_Open( LPCSTR filename
)
535 DOS_FULL_NAME full_name
;
536 char buffer
[MAX_PATHNAME_LEN
];
537 char *newdos_name
, *p
;
541 PROFILE
*tempProfile
;
543 /* First time around */
546 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
548 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
549 if(MRUProfile
[i
] == NULL
) break;
550 MRUProfile
[i
]->changed
=FALSE
;
551 MRUProfile
[i
]->section
=NULL
;
552 MRUProfile
[i
]->dos_name
=NULL
;
553 MRUProfile
[i
]->unix_name
=NULL
;
554 MRUProfile
[i
]->filename
=NULL
;
555 MRUProfile
[i
]->mtime
=0;
558 /* Check for a match */
560 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
561 strchr( filename
, ':' ))
563 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
567 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
568 strcat( buffer
, "\\" );
569 strcat( buffer
, filename
);
570 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
573 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
575 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
576 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
581 tempProfile
=MRUProfile
[i
];
583 MRUProfile
[j
]=MRUProfile
[j
-1];
584 CurProfile
=tempProfile
;
586 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
587 TRACE("(%s): already opened (mru=%d)\n",
590 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
596 /* Flush the old current profile */
599 /* Make the oldest profile the current one only in order to get rid of it */
600 if(i
==N_CACHED_PROFILES
)
602 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
603 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
604 MRUProfile
[i
]=MRUProfile
[i
-1];
605 CurProfile
=tempProfile
;
607 if(CurProfile
->filename
) PROFILE_ReleaseFile();
609 /* OK, now that CurProfile is definitely free we assign it our new file */
610 newdos_name
= HEAP_strdupA( GetProcessHeap(), 0, full_name
.short_name
);
611 CurProfile
->dos_name
= newdos_name
;
612 CurProfile
->filename
= HEAP_strdupA( GetProcessHeap(), 0, filename
);
614 /* Try to open the profile file, first in $HOME/.wine */
616 /* FIXME: this will need a more general solution */
617 strcpy( buffer
, get_config_dir() );
618 p
= buffer
+ strlen(buffer
);
620 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
622 if ((file
= fopen( buffer
, "r" )))
624 TRACE("(%s): found it in %s\n",
626 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
631 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0,
632 full_name
.long_name
);
633 if ((file
= fopen( full_name
.long_name
, "r" )))
634 TRACE("(%s): found it in %s\n",
635 filename
, full_name
.long_name
);
640 CurProfile
->section
= PROFILE_Load( file
);
642 if(!stat(CurProfile
->unix_name
,&buf
))
643 CurProfile
->mtime
=buf
.st_mtime
;
647 /* Does not exist yet, we will create it in PROFILE_FlushFile */
648 WARN("profile file %s not found\n", newdos_name
);
654 /***********************************************************************
657 * Returns all keys of a section.
658 * If return_values is TRUE, also include the corresponding values.
660 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
661 LPSTR buffer
, UINT len
, BOOL handle_env
,
667 if (section
->name
&& !strcasecmp( section
->name
, section_name
))
670 for (key
= section
->key
; key
; key
= key
->next
)
673 if (!*key
->name
) continue; /* Skip empty lines */
674 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
675 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
676 len
-= strlen(buffer
) + 1;
677 buffer
+= strlen(buffer
) + 1;
678 if (return_values
&& key
->value
) {
680 PROFILE_CopyEntry ( buffer
,
681 key
->value
, len
- 1, handle_env
);
682 len
-= strlen(buffer
) + 1;
683 buffer
+= strlen(buffer
) + 1;
688 /*If either lpszSection or lpszKey is NULL and the supplied
689 destination buffer is too small to hold all the strings,
690 the last string is truncated and followed by two null characters.
691 In this case, the return value is equal to cchReturnBuffer
699 section
= section
->next
;
701 buffer
[0] = buffer
[1] = '\0';
706 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
710 PROFILESECTION
*section
;
712 for (section
= CurProfile
->section
; section
; section
= section
->next
)
714 l
= strlen(section
->name
);
719 strcpy(buf
, section
->name
);
729 /***********************************************************************
732 * Get a profile string.
734 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
735 LPCSTR def_val
, LPSTR buffer
, UINT len
)
737 PROFILEKEY
*key
= NULL
;
739 if (!def_val
) def_val
= "";
740 if (key_name
&& key_name
[0])
742 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
743 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
745 TRACE("('%s','%s','%s'): returning '%s'\n",
746 section
, key_name
, def_val
, buffer
);
747 return strlen( buffer
);
749 if (key_name
&& !(key_name
[0]))
750 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
752 if (section
&& section
[0])
753 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
755 /* undocumented; both section and key_name are NULL */
756 return PROFILE_GetSectionNames(buffer
, len
);
760 /***********************************************************************
763 * Set a profile string.
765 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
768 if (!key_name
) /* Delete a whole section */
770 TRACE("('%s')\n", section_name
);
771 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
773 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
774 this is not an error on application's level.*/
776 else if (!value
) /* Delete a key */
778 TRACE("('%s','%s')\n",
779 section_name
, key_name
);
780 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
781 section_name
, key_name
);
782 return TRUE
; /* same error handling as above */
784 else /* Set the key value */
786 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
788 TRACE("('%s','%s','%s'): \n",
789 section_name
, key_name
, value
);
790 if (!key
) return FALSE
;
793 /* strip the leading spaces. We can safely strip \n\r and
794 * friends too, they should not happen here anyway. */
795 while (PROFILE_isspace(*value
)) value
++;
797 if (!strcmp( key
->value
, value
))
799 TRACE(" no change needed\n" );
800 return TRUE
; /* No change needed */
802 TRACE(" replacing '%s'\n", key
->value
);
803 HeapFree( GetProcessHeap(), 0, key
->value
);
805 else TRACE(" creating key\n" );
806 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
807 CurProfile
->changed
= TRUE
;
813 /***********************************************************************
814 * PROFILE_GetWineIniString
816 * Get a config string from the wine.ini file.
818 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
819 const char *def
, char *buffer
, int len
)
821 char tmp
[PROFILE_MAX_LINE_LEN
];
825 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
828 DWORD count
= sizeof(tmp
);
829 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
832 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
833 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
834 return strlen(buffer
);
838 /***********************************************************************
839 * PROFILE_EnumWineIniString
841 * Get a config string from the wine.ini file.
843 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
844 char *name
, int name_len
, char *buffer
, int len
)
846 char tmp
[PROFILE_MAX_LINE_LEN
];
849 DWORD count
= sizeof(tmp
);
851 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
852 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
856 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
857 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
863 /***********************************************************************
864 * PROFILE_GetWineIniInt
866 * Get a config integer from the wine.ini file.
868 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
874 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
875 if (!buffer
[0]) return def
;
876 result
= strtol( buffer
, &p
, 0 );
877 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
881 /******************************************************************************
883 * int PROFILE_GetWineIniBool(
884 * char const *section,
885 * char const *key_name,
888 * Reads a boolean value from the wine.ini file. This function attempts to
889 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
890 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
891 * true. Anything else results in the return of the default value.
893 * This function uses 1 to indicate true, and 0 for false. You can check
894 * for existence by setting def to something other than 0 or 1 and
895 * examining the return value.
897 int PROFILE_GetWineIniBool(
899 char const *key_name
,
905 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
907 switch(key_value
[0]) {
928 TRACE("(\"%s\", \"%s\", %s), "
929 "[%c], ret %s.\n", section
, key_name
,
930 def
? "TRUE" : "FALSE", key_value
[0],
931 retval
? "TRUE" : "FALSE");
937 /***********************************************************************
938 * PROFILE_LoadWineIni
940 * Load the wine.ini file.
942 int PROFILE_LoadWineIni(void)
944 char buffer
[MAX_PATHNAME_LEN
];
949 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
950 if (RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine", &hKeySW
))
952 ERR("Cannot create config registry key\n" );
955 RegCloseKey( hKeySW
);
956 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config", 0, NULL
,
957 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &wine_profile_key
, NULL
))
959 ERR("Cannot create config registry key\n" );
963 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
965 if ( (Options
.configFileName
!=NULL
) && (f
= fopen(Options
.configFileName
, "r")) )
967 /* Open -config specified file */
968 lstrcpynA(PROFILE_WineIniUsed
,Options
.configFileName
,MAX_PATHNAME_LEN
);
972 if ( (p
= getenv( "WINE_INI" )) && (f
= fopen( p
, "r" )) )
974 lstrcpynA(PROFILE_WineIniUsed
,p
,MAX_PATHNAME_LEN
);
977 if ((p
= getenv( "HOME" )) != NULL
)
979 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
980 strcat( buffer
, PROFILE_WineIniName
);
981 if ((f
= fopen( buffer
, "r" )) != NULL
)
983 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
987 else WARN("could not get $HOME value for config file.\n" );
989 /* Try global file */
991 if ((f
= fopen( WINE_INI_GLOBAL
, "r" )) != NULL
)
993 lstrcpynA(PROFILE_WineIniUsed
,WINE_INI_GLOBAL
,MAX_PATHNAME_LEN
);
996 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
997 WINE_INI_GLOBAL
, PROFILE_WineIniName
);
1001 PROFILE_RegistryLoad( wine_profile_key
, f
);
1007 /***********************************************************************
1008 * PROFILE_UsageWineIni
1010 * Explain the wine.ini file to those who don't read documentation.
1011 * Keep below one screenful in length so that error messages above are
1014 void PROFILE_UsageWineIni(void)
1016 MESSAGE("Perhaps you have not properly edited or created "
1017 "your Wine configuration file.\n");
1018 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL
,PROFILE_WineIniName
);
1019 MESSAGE(" or it is determined by the -config option or from\n"
1020 " the WINE_INI environment variable.\n");
1021 if (*PROFILE_WineIniUsed
)
1022 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed
);
1023 /* RTFM, so to say */
1026 /***********************************************************************
1027 * PROFILE_GetStringItem
1029 * Convenience function that turns a string 'xxx, yyy, zzz' into
1030 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1032 char* PROFILE_GetStringItem( char* start
)
1036 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1040 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1042 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1044 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1047 if( lpch
) *lpch
= '\0';
1051 /********************* API functions **********************************/
1053 /***********************************************************************
1054 * GetProfileInt16 (KERNEL.57)
1056 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1058 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1062 /***********************************************************************
1063 * GetProfileIntA (KERNEL32.264)
1065 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1067 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1070 /***********************************************************************
1071 * GetProfileIntW (KERNEL32.264)
1073 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1075 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1078 /***********************************************************************
1079 * GetProfileString16 (KERNEL.58)
1081 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1082 LPSTR buffer
, UINT16 len
)
1084 return GetPrivateProfileString16( section
, entry
, def_val
,
1085 buffer
, len
, "win.ini" );
1088 /***********************************************************************
1089 * GetProfileStringA (KERNEL32.268)
1091 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1092 LPSTR buffer
, UINT len
)
1094 return GetPrivateProfileStringA( section
, entry
, def_val
,
1095 buffer
, len
, "win.ini" );
1098 /***********************************************************************
1099 * GetProfileStringW (KERNEL32.269)
1101 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1102 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1104 return GetPrivateProfileStringW( section
, entry
, def_val
,
1105 buffer
, len
, wininiW
);
1108 /***********************************************************************
1109 * WriteProfileString16 (KERNEL.59)
1111 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1114 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1117 /***********************************************************************
1118 * WriteProfileStringA (KERNEL32.587)
1120 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1123 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1126 /***********************************************************************
1127 * WriteProfileStringW (KERNEL32.588)
1129 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1132 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1136 /***********************************************************************
1137 * GetPrivateProfileInt16 (KERNEL.127)
1139 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1140 INT16 def_val
, LPCSTR filename
)
1142 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1144 if (result
> 65535) return 65535;
1145 if (result
>= 0) return (UINT16
)result
;
1146 if (result
< -32768) return -32768;
1147 return (UINT16
)(INT16
)result
;
1150 /***********************************************************************
1151 * GetPrivateProfileIntA (KERNEL32.251)
1153 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1154 INT def_val
, LPCSTR filename
)
1160 GetPrivateProfileStringA( section
, entry
, "",
1161 buffer
, sizeof(buffer
), filename
);
1162 if (!buffer
[0]) return (UINT
)def_val
;
1163 result
= strtol( buffer
, &p
, 0 );
1164 if (p
== buffer
) return 0; /* No digits at all */
1165 return (UINT
)result
;
1168 /***********************************************************************
1169 * GetPrivateProfileIntW (KERNEL32.252)
1171 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1172 INT def_val
, LPCWSTR filename
)
1174 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1175 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1176 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1177 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1178 HeapFree( GetProcessHeap(), 0, sectionA
);
1179 HeapFree( GetProcessHeap(), 0, filenameA
);
1180 HeapFree( GetProcessHeap(), 0, entryA
);
1184 /***********************************************************************
1185 * GetPrivateProfileString16 (KERNEL.128)
1187 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1188 LPCSTR def_val
, LPSTR buffer
,
1189 UINT16 len
, LPCSTR filename
)
1191 return GetPrivateProfileStringA(section
,entry
,def_val
,buffer
,len
,filename
);
1194 /***********************************************************************
1195 * GetPrivateProfileStringA (KERNEL32.255)
1197 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1198 LPCSTR def_val
, LPSTR buffer
,
1199 UINT len
, LPCSTR filename
)
1204 filename
= "win.ini";
1206 EnterCriticalSection( &PROFILE_CritSect
);
1208 if (PROFILE_Open( filename
)) {
1209 ret
= PROFILE_GetString( section
, entry
, def_val
, buffer
, len
);
1211 lstrcpynA( buffer
, def_val
, len
);
1212 ret
= strlen( buffer
);
1215 LeaveCriticalSection( &PROFILE_CritSect
);
1220 /***********************************************************************
1221 * GetPrivateProfileStringW (KERNEL32.256)
1223 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1224 LPCWSTR def_val
, LPWSTR buffer
,
1225 UINT len
, LPCWSTR filename
)
1227 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1228 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1229 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1230 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1231 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1232 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1233 bufferA
, len
, filenameA
);
1234 lstrcpynAtoW( buffer
, bufferA
, len
);
1235 HeapFree( GetProcessHeap(), 0, sectionA
);
1236 HeapFree( GetProcessHeap(), 0, entryA
);
1237 HeapFree( GetProcessHeap(), 0, filenameA
);
1238 HeapFree( GetProcessHeap(), 0, def_valA
);
1239 HeapFree( GetProcessHeap(), 0, bufferA
);
1243 /***********************************************************************
1244 * GetPrivateProfileSection16 (KERNEL.418)
1246 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1247 UINT16 len
, LPCSTR filename
)
1249 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1252 /***********************************************************************
1253 * GetPrivateProfileSectionA (KERNEL32.255)
1255 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1256 DWORD len
, LPCSTR filename
)
1260 EnterCriticalSection( &PROFILE_CritSect
);
1262 if (PROFILE_Open( filename
))
1263 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1266 LeaveCriticalSection( &PROFILE_CritSect
);
1271 /***********************************************************************
1272 * GetPrivateProfileSectionW (KERNEL32.256)
1275 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1276 DWORD len
, LPCWSTR filename
)
1279 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1280 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1281 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1282 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1284 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1285 HeapFree( GetProcessHeap(), 0, sectionA
);
1286 HeapFree( GetProcessHeap(), 0, filenameA
);
1287 HeapFree( GetProcessHeap(), 0, bufferA
);
1291 /***********************************************************************
1292 * GetProfileSection16 (KERNEL.419)
1294 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1296 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1299 /***********************************************************************
1300 * GetProfileSectionA (KERNEL32.268)
1302 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1304 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1307 /***********************************************************************
1308 * GetProfileSectionW (KERNEL32)
1310 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1312 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1316 /***********************************************************************
1317 * WritePrivateProfileString16 (KERNEL.129)
1319 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1320 LPCSTR string
, LPCSTR filename
)
1322 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1325 /***********************************************************************
1326 * WritePrivateProfileStringA (KERNEL32.582)
1328 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1329 LPCSTR string
, LPCSTR filename
)
1333 EnterCriticalSection( &PROFILE_CritSect
);
1335 if (PROFILE_Open( filename
))
1337 if (!section
&& !entry
&& !string
)
1338 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1340 ret
= PROFILE_SetString( section
, entry
, string
);
1343 LeaveCriticalSection( &PROFILE_CritSect
);
1347 /***********************************************************************
1348 * WritePrivateProfileStringW (KERNEL32.583)
1350 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1351 LPCWSTR string
, LPCWSTR filename
)
1353 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1354 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1355 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1356 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1357 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1358 stringA
, filenameA
);
1359 HeapFree( GetProcessHeap(), 0, sectionA
);
1360 HeapFree( GetProcessHeap(), 0, entryA
);
1361 HeapFree( GetProcessHeap(), 0, stringA
);
1362 HeapFree( GetProcessHeap(), 0, filenameA
);
1366 /***********************************************************************
1367 * WritePrivateProfileSection16 (KERNEL.416)
1369 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1370 LPCSTR string
, LPCSTR filename
)
1372 return WritePrivateProfileSectionA( section
, string
, filename
);
1375 /***********************************************************************
1376 * WritePrivateProfileSectionA (KERNEL32)
1378 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1379 LPCSTR string
, LPCSTR filename
)
1384 EnterCriticalSection( &PROFILE_CritSect
);
1386 if (PROFILE_Open( filename
)) {
1387 if (!section
&& !string
&& !filename
)
1388 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1391 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1392 if((p
=strchr( buf
, '='))){
1394 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1397 HeapFree( GetProcessHeap(), 0, buf
);
1398 string
+= strlen(string
)+1;
1404 LeaveCriticalSection( &PROFILE_CritSect
);
1408 /***********************************************************************
1409 * WritePrivateProfileSectionW (KERNEL32)
1411 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1412 LPCWSTR string
, LPCWSTR filename
)
1415 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1416 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1417 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1418 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1419 HeapFree( GetProcessHeap(), 0, sectionA
);
1420 HeapFree( GetProcessHeap(), 0, stringA
);
1421 HeapFree( GetProcessHeap(), 0, filenameA
);
1425 /***********************************************************************
1426 * WriteProfileSection16 (KERNEL.417)
1428 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1430 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1433 /***********************************************************************
1434 * WriteProfileSectionA (KERNEL32.747)
1436 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1439 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1442 /***********************************************************************
1443 * WriteProfileSectionW (KERNEL32.748)
1445 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1447 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1450 /***********************************************************************
1451 * GetPrivateProfileSectionNames16 (KERNEL.143)
1453 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1458 EnterCriticalSection( &PROFILE_CritSect
);
1460 if (PROFILE_Open( filename
))
1461 ret
= PROFILE_GetSectionNames(buffer
, size
);
1463 LeaveCriticalSection( &PROFILE_CritSect
);
1469 /***********************************************************************
1470 * GetProfileSectionNames16 (KERNEL.142)
1472 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1475 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1479 /***********************************************************************
1480 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1482 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1486 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1490 /***********************************************************************
1491 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1493 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1497 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1498 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1500 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1501 lstrcpynAtoW( buffer
, bufferA
, size
);
1502 HeapFree( GetProcessHeap(), 0, bufferA
);
1503 HeapFree( GetProcessHeap(), 0, filenameA
);
1508 /***********************************************************************
1509 * GetPrivateProfileStruct16 (KERNEL.407)
1511 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1512 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1514 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1517 /***********************************************************************
1518 * GetPrivateProfileStructA (KERNEL32.370)
1520 * Should match Win95's behaviour pretty much
1522 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1523 LPVOID buf
, UINT len
, LPCSTR filename
)
1527 EnterCriticalSection( &PROFILE_CritSect
);
1529 if (PROFILE_Open( filename
)) {
1530 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1532 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1533 if (((strlen(k
->value
) - 2) / 2) == len
)
1540 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1541 /* check for invalid chars in ASCII coded hex string */
1542 for (p
=k
->value
; p
< end
; p
++)
1546 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1547 *p
, filename
, section
, key
);
1554 BOOL highnibble
= TRUE
;
1556 LPBYTE binbuf
= (LPBYTE
)buf
;
1558 end
-= 2; /* don't include checksum in output data */
1559 /* translate ASCII hex format into binary data */
1560 for (p
=k
->value
; p
< end
; p
++)
1564 (c
- 'A' + 10) : (c
- '0');
1571 *binbuf
++ = b
; /* feed binary data into output */
1572 chksum
+= b
; /* calculate checksum */
1574 highnibble
^= 1; /* toggle */
1576 /* retrieve stored checksum value */
1578 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1580 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1581 if (b
== (chksum
& 0xff)) /* checksums match ? */
1587 LeaveCriticalSection( &PROFILE_CritSect
);
1592 /***********************************************************************
1593 * GetPrivateProfileStructW (KERNEL32.543)
1595 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1596 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1598 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1599 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1600 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1601 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1603 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1605 lstrcpynAtoW( buffer
, bufferA
, len
);
1606 HeapFree( GetProcessHeap(), 0, bufferA
);
1607 HeapFree( GetProcessHeap(), 0, sectionA
);
1608 HeapFree( GetProcessHeap(), 0, keyA
);
1609 HeapFree( GetProcessHeap(), 0, filenameA
);
1616 /***********************************************************************
1617 * WritePrivateProfileStruct16 (KERNEL.406)
1619 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1620 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1622 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1625 /***********************************************************************
1626 * WritePrivateProfileStructA (KERNEL32.744)
1628 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1629 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1636 if (!section
&& !key
&& !buf
) /* flush the cache */
1637 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1639 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1640 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1642 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1643 *p
++ = hex
[*binbuf
>> 4];
1644 *p
++ = hex
[*binbuf
& 0xf];
1647 /* checksum is sum & 0xff */
1648 *p
++ = hex
[(sum
& 0xf0) >> 4];
1649 *p
++ = hex
[sum
& 0xf];
1652 EnterCriticalSection( &PROFILE_CritSect
);
1654 if (PROFILE_Open( filename
))
1655 ret
= PROFILE_SetString( section
, key
, outstring
);
1657 LeaveCriticalSection( &PROFILE_CritSect
);
1659 HeapFree( GetProcessHeap(), 0, outstring
);
1664 /***********************************************************************
1665 * WritePrivateProfileStructW (KERNEL32.544)
1667 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1668 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1670 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1671 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1672 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1673 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1675 HeapFree( GetProcessHeap(), 0, sectionA
);
1676 HeapFree( GetProcessHeap(), 0, keyA
);
1677 HeapFree( GetProcessHeap(), 0, filenameA
);
1683 /***********************************************************************
1684 * WriteOutProfiles (KERNEL.315)
1686 void WINAPI
WriteOutProfiles16(void)
1688 EnterCriticalSection( &PROFILE_CritSect
);
1689 PROFILE_FlushFile();
1690 LeaveCriticalSection( &PROFILE_CritSect
);
1693 /***********************************************************************
1694 * CloseProfileUserMapping (KERNEL.138)
1696 BOOL WINAPI
CloseProfileUserMapping(void) {
1697 FIXME("(), stub!\n");
1698 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);