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
;
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 exists as non-volatile key */
935 if (RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software", &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" );
947 wine_profile_key
= ConvertToGlobalHandle( wine_profile_key
);
949 InitializeCriticalSection( &PROFILE_CritSect
);
950 MakeCriticalSectionGlobal( &PROFILE_CritSect
);
952 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
954 if ( (Options
.configFileName
!=NULL
) && (f
= fopen(Options
.configFileName
, "r")) )
956 /* Open -config specified file */
957 lstrcpynA(PROFILE_WineIniUsed
,Options
.configFileName
,MAX_PATHNAME_LEN
);
961 if ( (p
= getenv( "WINE_INI" )) && (f
= fopen( p
, "r" )) )
963 lstrcpynA(PROFILE_WineIniUsed
,p
,MAX_PATHNAME_LEN
);
966 if ((p
= getenv( "HOME" )) != NULL
)
968 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
969 strcat( buffer
, PROFILE_WineIniName
);
970 if ((f
= fopen( buffer
, "r" )) != NULL
)
972 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
976 else WARN("could not get $HOME value for config file.\n" );
978 /* Try global file */
980 if ((f
= fopen( WINE_INI_GLOBAL
, "r" )) != NULL
)
982 lstrcpynA(PROFILE_WineIniUsed
,WINE_INI_GLOBAL
,MAX_PATHNAME_LEN
);
985 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
986 WINE_INI_GLOBAL
, PROFILE_WineIniName
);
990 PROFILE_RegistryLoad( wine_profile_key
, f
);
996 /***********************************************************************
997 * PROFILE_UsageWineIni
999 * Explain the wine.ini file to those who don't read documentation.
1000 * Keep below one screenful in length so that error messages above are
1003 void PROFILE_UsageWineIni(void)
1005 MESSAGE("Perhaps you have not properly edited or created "
1006 "your Wine configuration file.\n");
1007 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL
,PROFILE_WineIniName
);
1008 MESSAGE(" or it is determined by the -config option or from\n"
1009 " the WINE_INI environment variable.\n");
1010 if (*PROFILE_WineIniUsed
)
1011 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed
);
1012 /* RTFM, so to say */
1015 /***********************************************************************
1016 * PROFILE_GetStringItem
1018 * Convenience function that turns a string 'xxx, yyy, zzz' into
1019 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1021 char* PROFILE_GetStringItem( char* start
)
1025 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1029 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1031 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1033 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1036 if( lpch
) *lpch
= '\0';
1040 /********************* API functions **********************************/
1042 /***********************************************************************
1043 * GetProfileInt16 (KERNEL.57)
1045 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1047 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1051 /***********************************************************************
1052 * GetProfileIntA (KERNEL32.264)
1054 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1056 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1059 /***********************************************************************
1060 * GetProfileIntW (KERNEL32.264)
1062 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1064 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1067 /***********************************************************************
1068 * GetProfileString16 (KERNEL.58)
1070 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1071 LPSTR buffer
, UINT16 len
)
1073 return GetPrivateProfileString16( section
, entry
, def_val
,
1074 buffer
, len
, "win.ini" );
1077 /***********************************************************************
1078 * GetProfileStringA (KERNEL32.268)
1080 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1081 LPSTR buffer
, UINT len
)
1083 return GetPrivateProfileStringA( section
, entry
, def_val
,
1084 buffer
, len
, "win.ini" );
1087 /***********************************************************************
1088 * GetProfileStringW (KERNEL32.269)
1090 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1091 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1093 return GetPrivateProfileStringW( section
, entry
, def_val
,
1094 buffer
, len
, wininiW
);
1097 /***********************************************************************
1098 * WriteProfileString16 (KERNEL.59)
1100 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1103 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1106 /***********************************************************************
1107 * WriteProfileStringA (KERNEL32.587)
1109 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1112 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1115 /***********************************************************************
1116 * WriteProfileStringW (KERNEL32.588)
1118 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1121 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1125 /***********************************************************************
1126 * GetPrivateProfileInt16 (KERNEL.127)
1128 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1129 INT16 def_val
, LPCSTR filename
)
1131 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1133 if (result
> 65535) return 65535;
1134 if (result
>= 0) return (UINT16
)result
;
1135 if (result
< -32768) return -32768;
1136 return (UINT16
)(INT16
)result
;
1139 /***********************************************************************
1140 * GetPrivateProfileIntA (KERNEL32.251)
1142 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1143 INT def_val
, LPCSTR filename
)
1149 GetPrivateProfileStringA( section
, entry
, "",
1150 buffer
, sizeof(buffer
), filename
);
1151 if (!buffer
[0]) return (UINT
)def_val
;
1152 result
= strtol( buffer
, &p
, 0 );
1153 if (p
== buffer
) return 0; /* No digits at all */
1154 return (UINT
)result
;
1157 /***********************************************************************
1158 * GetPrivateProfileIntW (KERNEL32.252)
1160 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1161 INT def_val
, LPCWSTR filename
)
1163 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1164 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1165 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1166 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1167 HeapFree( GetProcessHeap(), 0, sectionA
);
1168 HeapFree( GetProcessHeap(), 0, filenameA
);
1169 HeapFree( GetProcessHeap(), 0, entryA
);
1173 /***********************************************************************
1174 * GetPrivateProfileString16 (KERNEL.128)
1176 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1177 LPCSTR def_val
, LPSTR buffer
,
1178 UINT16 len
, LPCSTR filename
)
1180 return GetPrivateProfileStringA(section
,entry
,def_val
,buffer
,len
,filename
);
1183 /***********************************************************************
1184 * GetPrivateProfileStringA (KERNEL32.255)
1186 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1187 LPCSTR def_val
, LPSTR buffer
,
1188 UINT len
, LPCSTR filename
)
1193 filename
= "win.ini";
1195 EnterCriticalSection( &PROFILE_CritSect
);
1197 if (PROFILE_Open( filename
)) {
1198 ret
= PROFILE_GetString( section
, entry
, def_val
, buffer
, len
);
1200 lstrcpynA( buffer
, def_val
, len
);
1201 ret
= strlen( buffer
);
1204 LeaveCriticalSection( &PROFILE_CritSect
);
1209 /***********************************************************************
1210 * GetPrivateProfileStringW (KERNEL32.256)
1212 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1213 LPCWSTR def_val
, LPWSTR buffer
,
1214 UINT len
, LPCWSTR filename
)
1216 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1217 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1218 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1219 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1220 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1221 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1222 bufferA
, len
, filenameA
);
1223 lstrcpynAtoW( buffer
, bufferA
, len
);
1224 HeapFree( GetProcessHeap(), 0, sectionA
);
1225 HeapFree( GetProcessHeap(), 0, entryA
);
1226 HeapFree( GetProcessHeap(), 0, filenameA
);
1227 HeapFree( GetProcessHeap(), 0, def_valA
);
1228 HeapFree( GetProcessHeap(), 0, bufferA
);
1232 /***********************************************************************
1233 * GetPrivateProfileSection16 (KERNEL.418)
1235 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1236 UINT16 len
, LPCSTR filename
)
1238 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1241 /***********************************************************************
1242 * GetPrivateProfileSectionA (KERNEL32.255)
1244 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1245 DWORD len
, LPCSTR filename
)
1249 EnterCriticalSection( &PROFILE_CritSect
);
1251 if (PROFILE_Open( filename
))
1252 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1255 LeaveCriticalSection( &PROFILE_CritSect
);
1260 /***********************************************************************
1261 * GetPrivateProfileSectionW (KERNEL32.256)
1264 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1265 DWORD len
, LPCWSTR filename
)
1268 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1269 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1270 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1271 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1273 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1274 HeapFree( GetProcessHeap(), 0, sectionA
);
1275 HeapFree( GetProcessHeap(), 0, filenameA
);
1276 HeapFree( GetProcessHeap(), 0, bufferA
);
1280 /***********************************************************************
1281 * GetProfileSection16 (KERNEL.419)
1283 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1285 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1288 /***********************************************************************
1289 * GetProfileSectionA (KERNEL32.268)
1291 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1293 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1296 /***********************************************************************
1297 * GetProfileSectionW (KERNEL32)
1299 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1301 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1305 /***********************************************************************
1306 * WritePrivateProfileString16 (KERNEL.129)
1308 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1309 LPCSTR string
, LPCSTR filename
)
1311 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1314 /***********************************************************************
1315 * WritePrivateProfileStringA (KERNEL32.582)
1317 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1318 LPCSTR string
, LPCSTR filename
)
1322 EnterCriticalSection( &PROFILE_CritSect
);
1324 if (PROFILE_Open( filename
))
1326 if (!section
&& !entry
&& !string
)
1327 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1329 ret
= PROFILE_SetString( section
, entry
, string
);
1332 LeaveCriticalSection( &PROFILE_CritSect
);
1336 /***********************************************************************
1337 * WritePrivateProfileStringW (KERNEL32.583)
1339 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1340 LPCWSTR string
, LPCWSTR filename
)
1342 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1343 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1344 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1345 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1346 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1347 stringA
, filenameA
);
1348 HeapFree( GetProcessHeap(), 0, sectionA
);
1349 HeapFree( GetProcessHeap(), 0, entryA
);
1350 HeapFree( GetProcessHeap(), 0, stringA
);
1351 HeapFree( GetProcessHeap(), 0, filenameA
);
1355 /***********************************************************************
1356 * WritePrivateProfileSection16 (KERNEL.416)
1358 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1359 LPCSTR string
, LPCSTR filename
)
1361 return WritePrivateProfileSectionA( section
, string
, filename
);
1364 /***********************************************************************
1365 * WritePrivateProfileSectionA (KERNEL32)
1367 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1368 LPCSTR string
, LPCSTR filename
)
1373 EnterCriticalSection( &PROFILE_CritSect
);
1375 if (PROFILE_Open( filename
)) {
1376 if (!section
&& !string
&& !filename
)
1377 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1380 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1381 if((p
=strchr( buf
, '='))){
1383 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1386 HeapFree( GetProcessHeap(), 0, buf
);
1387 string
+= strlen(string
)+1;
1393 LeaveCriticalSection( &PROFILE_CritSect
);
1397 /***********************************************************************
1398 * WritePrivateProfileSectionW (KERNEL32)
1400 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1401 LPCWSTR string
, LPCWSTR filename
)
1404 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1405 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1406 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1407 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1408 HeapFree( GetProcessHeap(), 0, sectionA
);
1409 HeapFree( GetProcessHeap(), 0, stringA
);
1410 HeapFree( GetProcessHeap(), 0, filenameA
);
1414 /***********************************************************************
1415 * WriteProfileSection16 (KERNEL.417)
1417 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1419 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1422 /***********************************************************************
1423 * WriteProfileSectionA (KERNEL32.747)
1425 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1428 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1431 /***********************************************************************
1432 * WriteProfileSectionW (KERNEL32.748)
1434 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1436 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1439 /***********************************************************************
1440 * GetPrivateProfileSectionNames16 (KERNEL.143)
1442 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1447 EnterCriticalSection( &PROFILE_CritSect
);
1449 if (PROFILE_Open( filename
))
1450 ret
= PROFILE_GetSectionNames(buffer
, size
);
1452 LeaveCriticalSection( &PROFILE_CritSect
);
1458 /***********************************************************************
1459 * GetProfileSectionNames16 (KERNEL.142)
1461 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1464 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1468 /***********************************************************************
1469 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1471 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1475 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1479 /***********************************************************************
1480 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1482 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1486 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1487 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1489 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1490 lstrcpynAtoW( buffer
, bufferA
, size
);
1491 HeapFree( GetProcessHeap(), 0, bufferA
);
1492 HeapFree( GetProcessHeap(), 0, filenameA
);
1497 /***********************************************************************
1498 * GetPrivateProfileStruct16 (KERNEL.407)
1500 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1501 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1503 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1506 /***********************************************************************
1507 * GetPrivateProfileStructA (KERNEL32.370)
1509 * Should match Win95's behaviour pretty much
1511 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1512 LPVOID buf
, UINT len
, LPCSTR filename
)
1516 EnterCriticalSection( &PROFILE_CritSect
);
1518 if (PROFILE_Open( filename
)) {
1519 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1521 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1522 if (((strlen(k
->value
) - 2) / 2) == len
)
1529 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1530 /* check for invalid chars in ASCII coded hex string */
1531 for (p
=k
->value
; p
< end
; p
++)
1535 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1536 *p
, filename
, section
, key
);
1543 BOOL highnibble
= TRUE
;
1545 LPBYTE binbuf
= (LPBYTE
)buf
;
1547 end
-= 2; /* don't include checksum in output data */
1548 /* translate ASCII hex format into binary data */
1549 for (p
=k
->value
; p
< end
; p
++)
1553 (c
- 'A' + 10) : (c
- '0');
1560 *binbuf
++ = b
; /* feed binary data into output */
1561 chksum
+= b
; /* calculate checksum */
1563 highnibble
^= 1; /* toggle */
1565 /* retrieve stored checksum value */
1567 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1569 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1570 if (b
== (chksum
& 0xff)) /* checksums match ? */
1576 LeaveCriticalSection( &PROFILE_CritSect
);
1581 /***********************************************************************
1582 * GetPrivateProfileStructW (KERNEL32.543)
1584 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1585 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1587 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1588 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1589 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1590 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1592 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1594 lstrcpynAtoW( buffer
, bufferA
, len
);
1595 HeapFree( GetProcessHeap(), 0, bufferA
);
1596 HeapFree( GetProcessHeap(), 0, sectionA
);
1597 HeapFree( GetProcessHeap(), 0, keyA
);
1598 HeapFree( GetProcessHeap(), 0, filenameA
);
1605 /***********************************************************************
1606 * WritePrivateProfileStruct16 (KERNEL.406)
1608 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1609 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1611 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1614 /***********************************************************************
1615 * WritePrivateProfileStructA (KERNEL32.744)
1617 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1618 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1625 if (!section
&& !key
&& !buf
) /* flush the cache */
1626 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1628 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1629 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1631 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1632 *p
++ = hex
[*binbuf
>> 4];
1633 *p
++ = hex
[*binbuf
& 0xf];
1636 /* checksum is sum & 0xff */
1637 *p
++ = hex
[(sum
& 0xf0) >> 4];
1638 *p
++ = hex
[sum
& 0xf];
1641 EnterCriticalSection( &PROFILE_CritSect
);
1643 if (PROFILE_Open( filename
))
1644 ret
= PROFILE_SetString( section
, key
, outstring
);
1646 LeaveCriticalSection( &PROFILE_CritSect
);
1648 HeapFree( GetProcessHeap(), 0, outstring
);
1653 /***********************************************************************
1654 * WritePrivateProfileStructW (KERNEL32.544)
1656 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1657 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1659 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1660 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1661 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1662 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1664 HeapFree( GetProcessHeap(), 0, sectionA
);
1665 HeapFree( GetProcessHeap(), 0, keyA
);
1666 HeapFree( GetProcessHeap(), 0, filenameA
);
1672 /***********************************************************************
1673 * WriteOutProfiles (KERNEL.315)
1675 void WINAPI
WriteOutProfiles16(void)
1677 EnterCriticalSection( &PROFILE_CritSect
);
1678 PROFILE_FlushFile();
1679 LeaveCriticalSection( &PROFILE_CritSect
);
1682 /***********************************************************************
1683 * CloseProfileUserMapping (KERNEL.138)
1685 BOOL WINAPI
CloseProfileUserMapping(void) {
1686 FIXME("(), stub!\n");
1687 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);