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
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section
) );
206 first_section
->name
= NULL
;
207 first_section
->key
= NULL
;
208 first_section
->next
= NULL
;
209 next_section
= &first_section
->next
;
210 next_key
= &first_section
->key
;
213 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
217 while (*p
&& PROFILE_isspace(*p
)) p
++;
218 if (*p
== '[') /* section start */
220 if (!(p2
= strrchr( p
, ']' )))
222 WARN("Invalid section header at line %d: '%s'\n",
229 section
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section
) );
230 section
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
232 section
->next
= NULL
;
233 *next_section
= section
;
234 next_section
= §ion
->next
;
235 next_key
= §ion
->key
;
238 TRACE("New section: '%s'\n",section
->name
);
245 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
247 if ((p2
= strchr( p
, '=' )) != NULL
)
250 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
252 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
255 if(*p
|| !prev_key
|| *prev_key
->name
)
257 key
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(*key
) );
258 key
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
259 key
->value
= p2
? HEAP_strdupA( GetProcessHeap(), 0, p2
) : NULL
;
262 next_key
= &key
->next
;
265 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
268 return first_section
;
272 /***********************************************************************
273 * PROFILE_RegistryLoad
275 * Load a profile tree from a file into a registry key.
277 static DWORD
PROFILE_RegistryLoad( HKEY root
, FILE *file
)
281 char buffer
[PROFILE_MAX_LINE_LEN
];
285 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
289 while (*p
&& PROFILE_isspace(*p
)) p
++;
290 if (*p
== '[') /* section start */
292 if (!(p2
= strrchr( p
, ']' )))
294 WARN("Invalid section header at line %d: '%s'\n",
301 if (hkey
) RegCloseKey( hkey
);
302 if ((err
= RegCreateKeyExA( root
, p
, 0, NULL
, REG_OPTION_VOLATILE
,
303 KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))) return err
;
304 TRACE("New section: '%s'\n",p
);
310 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
312 if ((p2
= strchr( p
, '=' )) != NULL
)
315 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
317 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
320 if (*p
&& hkey
&& !IS_ENTRY_COMMENT(p
))
323 if ((err
= RegSetValueExA( hkey
, p
, 0, REG_SZ
, p2
, strlen(p2
)+1 )))
328 TRACE("New key: name='%s', value='%s'\n",p
,p2
);
331 if (hkey
) RegCloseKey( hkey
);
336 /***********************************************************************
337 * PROFILE_DeleteSection
339 * Delete a section from a profile tree.
341 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
345 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, name
))
347 PROFILESECTION
*to_del
= *section
;
348 *section
= to_del
->next
;
350 PROFILE_Free( to_del
);
353 section
= &(*section
)->next
;
359 /***********************************************************************
362 * Delete a key from a profile tree.
364 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
365 LPCSTR section_name
, LPCSTR key_name
)
369 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
371 PROFILEKEY
**key
= &(*section
)->key
;
374 if (!strcasecmp( (*key
)->name
, key_name
))
376 PROFILEKEY
*to_del
= *key
;
378 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
379 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
380 HeapFree( GetProcessHeap(), 0, to_del
);
386 section
= &(*section
)->next
;
392 /***********************************************************************
395 * Find a key in a profile tree, optionally creating it.
397 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
,
398 const char *section_name
,
399 const char *key_name
, int create
)
404 while (PROFILE_isspace(*section_name
)) section_name
++;
405 p
= section_name
+ strlen(section_name
) - 1;
406 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
407 seclen
= p
- section_name
+ 1;
409 while (PROFILE_isspace(*key_name
)) key_name
++;
410 p
= key_name
+ strlen(key_name
) - 1;
411 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
412 keylen
= p
- key_name
+ 1;
416 if ( ((*section
)->name
)
417 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
418 && (((*section
)->name
)[seclen
] == '\0') )
420 PROFILEKEY
**key
= &(*section
)->key
;
423 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
424 && (((*key
)->name
)[keylen
] == '\0') )
428 if (!create
) return NULL
;
429 *key
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
430 (*key
)->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
431 (*key
)->value
= NULL
;
435 section
= &(*section
)->next
;
437 if (!create
) return NULL
;
438 *section
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) );
439 (*section
)->name
= HEAP_strdupA( GetProcessHeap(), 0, section_name
);
440 (*section
)->next
= NULL
;
441 (*section
)->key
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
442 (*section
)->key
->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
443 (*section
)->key
->value
= NULL
;
444 (*section
)->key
->next
= NULL
;
445 return (*section
)->key
;
449 /***********************************************************************
452 * Flush the current profile to disk if changed.
454 static BOOL
PROFILE_FlushFile(void)
456 char *p
, buffer
[MAX_PATHNAME_LEN
];
457 const char *unix_name
;
463 WARN("No current profile!\n");
467 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
468 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
470 /* Try to create it in $HOME/.wine */
471 /* FIXME: this will need a more general solution */
472 strcpy( buffer
, get_config_dir() );
473 p
= buffer
+ strlen(buffer
);
475 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
477 file
= fopen( buffer
, "w" );
483 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
487 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
488 PROFILE_Save( file
, CurProfile
->section
);
490 CurProfile
->changed
= FALSE
;
491 if(!stat(unix_name
,&buf
))
492 CurProfile
->mtime
=buf
.st_mtime
;
497 /***********************************************************************
498 * PROFILE_ReleaseFile
500 * Flush the current profile to disk and remove it from the cache.
502 static void PROFILE_ReleaseFile(void)
505 PROFILE_Free( CurProfile
->section
);
506 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
507 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
508 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
509 CurProfile
->changed
= FALSE
;
510 CurProfile
->section
= NULL
;
511 CurProfile
->dos_name
= NULL
;
512 CurProfile
->unix_name
= NULL
;
513 CurProfile
->filename
= NULL
;
514 CurProfile
->mtime
= 0;
518 /***********************************************************************
521 * Open a profile file, checking the cached file first.
523 static BOOL
PROFILE_Open( LPCSTR filename
)
525 DOS_FULL_NAME full_name
;
526 char buffer
[MAX_PATHNAME_LEN
];
527 char *newdos_name
, *p
;
531 PROFILE
*tempProfile
;
533 /* First time around */
536 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
538 MRUProfile
[i
]=HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
539 MRUProfile
[i
]->changed
=FALSE
;
540 MRUProfile
[i
]->section
=NULL
;
541 MRUProfile
[i
]->dos_name
=NULL
;
542 MRUProfile
[i
]->unix_name
=NULL
;
543 MRUProfile
[i
]->filename
=NULL
;
544 MRUProfile
[i
]->mtime
=0;
547 /* Check for a match */
549 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
550 strchr( filename
, ':' ))
552 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
556 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
557 strcat( buffer
, "\\" );
558 strcat( buffer
, filename
);
559 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
562 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
564 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
565 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
570 tempProfile
=MRUProfile
[i
];
572 MRUProfile
[j
]=MRUProfile
[j
-1];
573 CurProfile
=tempProfile
;
575 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
576 TRACE("(%s): already opened (mru=%d)\n",
579 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
585 /* Flush the old current profile */
588 /* Make the oldest profile the current one only in order to get rid of it */
589 if(i
==N_CACHED_PROFILES
)
591 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
592 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
593 MRUProfile
[i
]=MRUProfile
[i
-1];
594 CurProfile
=tempProfile
;
596 if(CurProfile
->filename
) PROFILE_ReleaseFile();
598 /* OK, now that CurProfile is definitely free we assign it our new file */
599 newdos_name
= HEAP_strdupA( GetProcessHeap(), 0, full_name
.short_name
);
600 CurProfile
->dos_name
= newdos_name
;
601 CurProfile
->filename
= HEAP_strdupA( GetProcessHeap(), 0, filename
);
603 /* Try to open the profile file, first in $HOME/.wine */
605 /* FIXME: this will need a more general solution */
606 strcpy( buffer
, get_config_dir() );
607 p
= buffer
+ strlen(buffer
);
609 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
611 if ((file
= fopen( buffer
, "r" )))
613 TRACE("(%s): found it in %s\n",
615 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
620 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0,
621 full_name
.long_name
);
622 if ((file
= fopen( full_name
.long_name
, "r" )))
623 TRACE("(%s): found it in %s\n",
624 filename
, full_name
.long_name
);
629 CurProfile
->section
= PROFILE_Load( file
);
631 if(!stat(CurProfile
->unix_name
,&buf
))
632 CurProfile
->mtime
=buf
.st_mtime
;
636 /* Does not exist yet, we will create it in PROFILE_FlushFile */
637 WARN("profile file %s not found\n", newdos_name
);
643 /***********************************************************************
646 * Returns all keys of a section.
647 * If return_values is TRUE, also include the corresponding values.
649 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
650 LPSTR buffer
, UINT len
, BOOL handle_env
,
656 if (section
->name
&& !strcasecmp( section
->name
, section_name
))
659 for (key
= section
->key
; key
; key
= key
->next
)
662 if (!*key
->name
) continue; /* Skip empty lines */
663 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
664 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
665 len
-= strlen(buffer
) + 1;
666 buffer
+= strlen(buffer
) + 1;
667 if (return_values
&& key
->value
) {
669 PROFILE_CopyEntry ( buffer
,
670 key
->value
, len
- 1, handle_env
);
671 len
-= strlen(buffer
) + 1;
672 buffer
+= strlen(buffer
) + 1;
677 /*If either lpszSection or lpszKey is NULL and the supplied
678 destination buffer is too small to hold all the strings,
679 the last string is truncated and followed by two null characters.
680 In this case, the return value is equal to cchReturnBuffer
688 section
= section
->next
;
690 buffer
[0] = buffer
[1] = '\0';
695 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
699 PROFILESECTION
*section
;
701 for (section
= CurProfile
->section
; section
; section
= section
->next
)
703 l
= strlen(section
->name
);
708 strcpy(buf
, section
->name
);
718 /***********************************************************************
721 * Get a profile string.
723 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
724 LPCSTR def_val
, LPSTR buffer
, UINT len
)
726 PROFILEKEY
*key
= NULL
;
728 if (!def_val
) def_val
= "";
729 if (key_name
&& key_name
[0])
731 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
732 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
734 TRACE("('%s','%s','%s'): returning '%s'\n",
735 section
, key_name
, def_val
, buffer
);
736 return strlen( buffer
);
738 if (key_name
&& !(key_name
[0]))
739 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
741 if (section
&& section
[0])
742 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
744 /* undocumented; both section and key_name are NULL */
745 return PROFILE_GetSectionNames(buffer
, len
);
749 /***********************************************************************
752 * Set a profile string.
754 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
757 if (!key_name
) /* Delete a whole section */
759 TRACE("('%s')\n", section_name
);
760 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
762 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
763 this is not an error on application's level.*/
765 else if (!value
) /* Delete a key */
767 TRACE("('%s','%s')\n",
768 section_name
, key_name
);
769 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
770 section_name
, key_name
);
771 return TRUE
; /* same error handling as above */
773 else /* Set the key value */
775 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
777 TRACE("('%s','%s','%s'): \n",
778 section_name
, key_name
, value
);
779 if (!key
) return FALSE
;
782 if (!strcmp( key
->value
, value
))
784 TRACE(" no change needed\n" );
785 return TRUE
; /* No change needed */
787 TRACE(" replacing '%s'\n", key
->value
);
788 HeapFree( GetProcessHeap(), 0, key
->value
);
790 else TRACE(" creating key\n" );
791 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
792 CurProfile
->changed
= TRUE
;
798 /***********************************************************************
799 * PROFILE_GetWineIniString
801 * Get a config string from the wine.ini file.
803 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
804 const char *def
, char *buffer
, int len
)
806 char tmp
[PROFILE_MAX_LINE_LEN
];
810 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
813 DWORD count
= sizeof(tmp
);
814 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
817 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
818 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
819 return strlen(buffer
);
823 /***********************************************************************
824 * PROFILE_EnumWineIniString
826 * Get a config string from the wine.ini file.
828 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
829 char *name
, int name_len
, char *buffer
, int len
)
831 char tmp
[PROFILE_MAX_LINE_LEN
];
834 DWORD count
= sizeof(tmp
);
836 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
837 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
841 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
842 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
848 /***********************************************************************
849 * PROFILE_GetWineIniInt
851 * Get a config integer from the wine.ini file.
853 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
859 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
860 if (!buffer
[0]) return def
;
861 result
= strtol( buffer
, &p
, 0 );
862 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
866 /******************************************************************************
868 * int PROFILE_GetWineIniBool(
869 * char const *section,
870 * char const *key_name,
873 * Reads a boolean value from the wine.ini file. This function attempts to
874 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
875 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
876 * true. Anything else results in the return of the default value.
878 * This function uses 1 to indicate true, and 0 for false. You can check
879 * for existence by setting def to something other than 0 or 1 and
880 * examining the return value.
882 int PROFILE_GetWineIniBool(
884 char const *key_name
,
890 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
892 switch(key_value
[0]) {
913 TRACE("(\"%s\", \"%s\", %s), "
914 "[%c], ret %s.\n", section
, key_name
,
915 def
? "TRUE" : "FALSE", key_value
[0],
916 retval
? "TRUE" : "FALSE");
922 /***********************************************************************
923 * PROFILE_LoadWineIni
925 * Load the wine.ini file.
927 int PROFILE_LoadWineIni(void)
929 char buffer
[MAX_PATHNAME_LEN
];
934 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
935 if (RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine", &hKeySW
))
937 ERR("Cannot create config registry key\n" );
940 RegCloseKey( hKeySW
);
941 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config", 0, NULL
,
942 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &wine_profile_key
, NULL
))
944 ERR("Cannot create config registry key\n" );
948 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
950 if ( (Options
.configFileName
!=NULL
) && (f
= fopen(Options
.configFileName
, "r")) )
952 /* Open -config specified file */
953 lstrcpynA(PROFILE_WineIniUsed
,Options
.configFileName
,MAX_PATHNAME_LEN
);
957 if ( (p
= getenv( "WINE_INI" )) && (f
= fopen( p
, "r" )) )
959 lstrcpynA(PROFILE_WineIniUsed
,p
,MAX_PATHNAME_LEN
);
962 if ((p
= getenv( "HOME" )) != NULL
)
964 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
965 strcat( buffer
, PROFILE_WineIniName
);
966 if ((f
= fopen( buffer
, "r" )) != NULL
)
968 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
972 else WARN("could not get $HOME value for config file.\n" );
974 /* Try global file */
976 if ((f
= fopen( WINE_INI_GLOBAL
, "r" )) != NULL
)
978 lstrcpynA(PROFILE_WineIniUsed
,WINE_INI_GLOBAL
,MAX_PATHNAME_LEN
);
981 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
982 WINE_INI_GLOBAL
, PROFILE_WineIniName
);
986 PROFILE_RegistryLoad( wine_profile_key
, f
);
992 /***********************************************************************
993 * PROFILE_UsageWineIni
995 * Explain the wine.ini file to those who don't read documentation.
996 * Keep below one screenful in length so that error messages above are
999 void PROFILE_UsageWineIni(void)
1001 MESSAGE("Perhaps you have not properly edited or created "
1002 "your Wine configuration file.\n");
1003 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL
,PROFILE_WineIniName
);
1004 MESSAGE(" or it is determined by the -config option or from\n"
1005 " the WINE_INI environment variable.\n");
1006 if (*PROFILE_WineIniUsed
)
1007 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed
);
1008 /* RTFM, so to say */
1011 /***********************************************************************
1012 * PROFILE_GetStringItem
1014 * Convenience function that turns a string 'xxx, yyy, zzz' into
1015 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1017 char* PROFILE_GetStringItem( char* start
)
1021 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1025 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1027 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1029 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1032 if( lpch
) *lpch
= '\0';
1036 /********************* API functions **********************************/
1038 /***********************************************************************
1039 * GetProfileInt16 (KERNEL.57)
1041 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1043 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1047 /***********************************************************************
1048 * GetProfileIntA (KERNEL32.264)
1050 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1052 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1055 /***********************************************************************
1056 * GetProfileIntW (KERNEL32.264)
1058 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1060 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1063 /***********************************************************************
1064 * GetProfileString16 (KERNEL.58)
1066 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1067 LPSTR buffer
, UINT16 len
)
1069 return GetPrivateProfileString16( section
, entry
, def_val
,
1070 buffer
, len
, "win.ini" );
1073 /***********************************************************************
1074 * GetProfileStringA (KERNEL32.268)
1076 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1077 LPSTR buffer
, UINT len
)
1079 return GetPrivateProfileStringA( section
, entry
, def_val
,
1080 buffer
, len
, "win.ini" );
1083 /***********************************************************************
1084 * GetProfileStringW (KERNEL32.269)
1086 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1087 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1089 return GetPrivateProfileStringW( section
, entry
, def_val
,
1090 buffer
, len
, wininiW
);
1093 /***********************************************************************
1094 * WriteProfileString16 (KERNEL.59)
1096 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1099 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1102 /***********************************************************************
1103 * WriteProfileStringA (KERNEL32.587)
1105 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1108 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1111 /***********************************************************************
1112 * WriteProfileStringW (KERNEL32.588)
1114 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1117 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1121 /***********************************************************************
1122 * GetPrivateProfileInt16 (KERNEL.127)
1124 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1125 INT16 def_val
, LPCSTR filename
)
1127 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1129 if (result
> 65535) return 65535;
1130 if (result
>= 0) return (UINT16
)result
;
1131 if (result
< -32768) return -32768;
1132 return (UINT16
)(INT16
)result
;
1135 /***********************************************************************
1136 * GetPrivateProfileIntA (KERNEL32.251)
1138 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1139 INT def_val
, LPCSTR filename
)
1145 GetPrivateProfileStringA( section
, entry
, "",
1146 buffer
, sizeof(buffer
), filename
);
1147 if (!buffer
[0]) return (UINT
)def_val
;
1148 result
= strtol( buffer
, &p
, 0 );
1149 if (p
== buffer
) return 0; /* No digits at all */
1150 return (UINT
)result
;
1153 /***********************************************************************
1154 * GetPrivateProfileIntW (KERNEL32.252)
1156 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1157 INT def_val
, LPCWSTR filename
)
1159 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1160 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1161 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1162 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1163 HeapFree( GetProcessHeap(), 0, sectionA
);
1164 HeapFree( GetProcessHeap(), 0, filenameA
);
1165 HeapFree( GetProcessHeap(), 0, entryA
);
1169 /***********************************************************************
1170 * GetPrivateProfileString16 (KERNEL.128)
1172 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1173 LPCSTR def_val
, LPSTR buffer
,
1174 UINT16 len
, LPCSTR filename
)
1176 return GetPrivateProfileStringA(section
,entry
,def_val
,buffer
,len
,filename
);
1179 /***********************************************************************
1180 * GetPrivateProfileStringA (KERNEL32.255)
1182 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1183 LPCSTR def_val
, LPSTR buffer
,
1184 UINT len
, LPCSTR filename
)
1189 filename
= "win.ini";
1191 EnterCriticalSection( &PROFILE_CritSect
);
1193 if (PROFILE_Open( filename
)) {
1194 ret
= PROFILE_GetString( section
, entry
, def_val
, buffer
, len
);
1196 lstrcpynA( buffer
, def_val
, len
);
1197 ret
= strlen( buffer
);
1200 LeaveCriticalSection( &PROFILE_CritSect
);
1205 /***********************************************************************
1206 * GetPrivateProfileStringW (KERNEL32.256)
1208 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1209 LPCWSTR def_val
, LPWSTR buffer
,
1210 UINT len
, LPCWSTR filename
)
1212 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1213 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1214 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1215 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1216 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1217 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1218 bufferA
, len
, filenameA
);
1219 lstrcpynAtoW( buffer
, bufferA
, len
);
1220 HeapFree( GetProcessHeap(), 0, sectionA
);
1221 HeapFree( GetProcessHeap(), 0, entryA
);
1222 HeapFree( GetProcessHeap(), 0, filenameA
);
1223 HeapFree( GetProcessHeap(), 0, def_valA
);
1224 HeapFree( GetProcessHeap(), 0, bufferA
);
1228 /***********************************************************************
1229 * GetPrivateProfileSection16 (KERNEL.418)
1231 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1232 UINT16 len
, LPCSTR filename
)
1234 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1237 /***********************************************************************
1238 * GetPrivateProfileSectionA (KERNEL32.255)
1240 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1241 DWORD len
, LPCSTR filename
)
1245 EnterCriticalSection( &PROFILE_CritSect
);
1247 if (PROFILE_Open( filename
))
1248 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1251 LeaveCriticalSection( &PROFILE_CritSect
);
1256 /***********************************************************************
1257 * GetPrivateProfileSectionW (KERNEL32.256)
1260 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1261 DWORD len
, LPCWSTR filename
)
1264 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1265 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1266 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1267 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1269 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1270 HeapFree( GetProcessHeap(), 0, sectionA
);
1271 HeapFree( GetProcessHeap(), 0, filenameA
);
1272 HeapFree( GetProcessHeap(), 0, bufferA
);
1276 /***********************************************************************
1277 * GetProfileSection16 (KERNEL.419)
1279 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1281 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1284 /***********************************************************************
1285 * GetProfileSectionA (KERNEL32.268)
1287 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1289 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1292 /***********************************************************************
1293 * GetProfileSectionW (KERNEL32)
1295 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1297 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1301 /***********************************************************************
1302 * WritePrivateProfileString16 (KERNEL.129)
1304 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1305 LPCSTR string
, LPCSTR filename
)
1307 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1310 /***********************************************************************
1311 * WritePrivateProfileStringA (KERNEL32.582)
1313 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1314 LPCSTR string
, LPCSTR filename
)
1318 EnterCriticalSection( &PROFILE_CritSect
);
1320 if (PROFILE_Open( filename
))
1322 if (!section
&& !entry
&& !string
)
1323 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1325 ret
= PROFILE_SetString( section
, entry
, string
);
1328 LeaveCriticalSection( &PROFILE_CritSect
);
1332 /***********************************************************************
1333 * WritePrivateProfileStringW (KERNEL32.583)
1335 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1336 LPCWSTR string
, LPCWSTR filename
)
1338 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1339 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1340 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1341 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1342 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1343 stringA
, filenameA
);
1344 HeapFree( GetProcessHeap(), 0, sectionA
);
1345 HeapFree( GetProcessHeap(), 0, entryA
);
1346 HeapFree( GetProcessHeap(), 0, stringA
);
1347 HeapFree( GetProcessHeap(), 0, filenameA
);
1351 /***********************************************************************
1352 * WritePrivateProfileSection16 (KERNEL.416)
1354 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1355 LPCSTR string
, LPCSTR filename
)
1357 return WritePrivateProfileSectionA( section
, string
, filename
);
1360 /***********************************************************************
1361 * WritePrivateProfileSectionA (KERNEL32)
1363 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1364 LPCSTR string
, LPCSTR filename
)
1369 EnterCriticalSection( &PROFILE_CritSect
);
1371 if (PROFILE_Open( filename
)) {
1372 if (!section
&& !string
&& !filename
)
1373 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1376 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1377 if((p
=strchr( buf
, '='))){
1379 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1382 HeapFree( GetProcessHeap(), 0, buf
);
1383 string
+= strlen(string
)+1;
1389 LeaveCriticalSection( &PROFILE_CritSect
);
1393 /***********************************************************************
1394 * WritePrivateProfileSectionW (KERNEL32)
1396 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1397 LPCWSTR string
, LPCWSTR filename
)
1400 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1401 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1402 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1403 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1404 HeapFree( GetProcessHeap(), 0, sectionA
);
1405 HeapFree( GetProcessHeap(), 0, stringA
);
1406 HeapFree( GetProcessHeap(), 0, filenameA
);
1410 /***********************************************************************
1411 * WriteProfileSection16 (KERNEL.417)
1413 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1415 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1418 /***********************************************************************
1419 * WriteProfileSectionA (KERNEL32.747)
1421 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1424 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1427 /***********************************************************************
1428 * WriteProfileSectionW (KERNEL32.748)
1430 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1432 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1435 /***********************************************************************
1436 * GetPrivateProfileSectionNames16 (KERNEL.143)
1438 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1443 EnterCriticalSection( &PROFILE_CritSect
);
1445 if (PROFILE_Open( filename
))
1446 ret
= PROFILE_GetSectionNames(buffer
, size
);
1448 LeaveCriticalSection( &PROFILE_CritSect
);
1454 /***********************************************************************
1455 * GetProfileSectionNames16 (KERNEL.142)
1457 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1460 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1464 /***********************************************************************
1465 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1467 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1471 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1475 /***********************************************************************
1476 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1478 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1482 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1483 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1485 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1486 lstrcpynAtoW( buffer
, bufferA
, size
);
1487 HeapFree( GetProcessHeap(), 0, bufferA
);
1488 HeapFree( GetProcessHeap(), 0, filenameA
);
1493 /***********************************************************************
1494 * GetPrivateProfileStruct16 (KERNEL.407)
1496 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1497 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1499 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1502 /***********************************************************************
1503 * GetPrivateProfileStructA (KERNEL32.370)
1505 * Should match Win95's behaviour pretty much
1507 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1508 LPVOID buf
, UINT len
, LPCSTR filename
)
1512 EnterCriticalSection( &PROFILE_CritSect
);
1514 if (PROFILE_Open( filename
)) {
1515 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1517 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1518 if (((strlen(k
->value
) - 2) / 2) == len
)
1525 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1526 /* check for invalid chars in ASCII coded hex string */
1527 for (p
=k
->value
; p
< end
; p
++)
1531 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1532 *p
, filename
, section
, key
);
1539 BOOL highnibble
= TRUE
;
1541 LPBYTE binbuf
= (LPBYTE
)buf
;
1543 end
-= 2; /* don't include checksum in output data */
1544 /* translate ASCII hex format into binary data */
1545 for (p
=k
->value
; p
< end
; p
++)
1549 (c
- 'A' + 10) : (c
- '0');
1556 *binbuf
++ = b
; /* feed binary data into output */
1557 chksum
+= b
; /* calculate checksum */
1559 highnibble
^= 1; /* toggle */
1561 /* retrieve stored checksum value */
1563 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1565 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1566 if (b
== (chksum
& 0xff)) /* checksums match ? */
1572 LeaveCriticalSection( &PROFILE_CritSect
);
1577 /***********************************************************************
1578 * GetPrivateProfileStructW (KERNEL32.543)
1580 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1581 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1583 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1584 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1585 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1586 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1588 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1590 lstrcpynAtoW( buffer
, bufferA
, len
);
1591 HeapFree( GetProcessHeap(), 0, bufferA
);
1592 HeapFree( GetProcessHeap(), 0, sectionA
);
1593 HeapFree( GetProcessHeap(), 0, keyA
);
1594 HeapFree( GetProcessHeap(), 0, filenameA
);
1601 /***********************************************************************
1602 * WritePrivateProfileStruct16 (KERNEL.406)
1604 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1605 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1607 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1610 /***********************************************************************
1611 * WritePrivateProfileStructA (KERNEL32.744)
1613 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1614 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1621 if (!section
&& !key
&& !buf
) /* flush the cache */
1622 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1624 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1625 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1627 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1628 *p
++ = hex
[*binbuf
>> 4];
1629 *p
++ = hex
[*binbuf
& 0xf];
1632 /* checksum is sum & 0xff */
1633 *p
++ = hex
[(sum
& 0xf0) >> 4];
1634 *p
++ = hex
[sum
& 0xf];
1637 EnterCriticalSection( &PROFILE_CritSect
);
1639 if (PROFILE_Open( filename
))
1640 ret
= PROFILE_SetString( section
, key
, outstring
);
1642 LeaveCriticalSection( &PROFILE_CritSect
);
1644 HeapFree( GetProcessHeap(), 0, outstring
);
1649 /***********************************************************************
1650 * WritePrivateProfileStructW (KERNEL32.544)
1652 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1653 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1655 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1656 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1657 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1658 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1660 HeapFree( GetProcessHeap(), 0, sectionA
);
1661 HeapFree( GetProcessHeap(), 0, keyA
);
1662 HeapFree( GetProcessHeap(), 0, filenameA
);
1668 /***********************************************************************
1669 * WriteOutProfiles (KERNEL.315)
1671 void WINAPI
WriteOutProfiles16(void)
1673 EnterCriticalSection( &PROFILE_CritSect
);
1674 PROFILE_FlushFile();
1675 LeaveCriticalSection( &PROFILE_CritSect
);
1678 /***********************************************************************
1679 * CloseProfileUserMapping (KERNEL.138)
1681 BOOL WINAPI
CloseProfileUserMapping(void) {
1682 FIXME("(), stub!\n");
1683 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);