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 if (!strcmp( key
->value
, value
))
795 TRACE(" no change needed\n" );
796 return TRUE
; /* No change needed */
798 TRACE(" replacing '%s'\n", key
->value
);
799 HeapFree( GetProcessHeap(), 0, key
->value
);
801 else TRACE(" creating key\n" );
802 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
803 CurProfile
->changed
= TRUE
;
809 /***********************************************************************
810 * PROFILE_GetWineIniString
812 * Get a config string from the wine.ini file.
814 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
815 const char *def
, char *buffer
, int len
)
817 char tmp
[PROFILE_MAX_LINE_LEN
];
821 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
824 DWORD count
= sizeof(tmp
);
825 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
828 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
829 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
830 return strlen(buffer
);
834 /***********************************************************************
835 * PROFILE_EnumWineIniString
837 * Get a config string from the wine.ini file.
839 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
840 char *name
, int name_len
, char *buffer
, int len
)
842 char tmp
[PROFILE_MAX_LINE_LEN
];
845 DWORD count
= sizeof(tmp
);
847 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
848 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
852 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
853 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
859 /***********************************************************************
860 * PROFILE_GetWineIniInt
862 * Get a config integer from the wine.ini file.
864 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
870 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
871 if (!buffer
[0]) return def
;
872 result
= strtol( buffer
, &p
, 0 );
873 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
877 /******************************************************************************
879 * int PROFILE_GetWineIniBool(
880 * char const *section,
881 * char const *key_name,
884 * Reads a boolean value from the wine.ini file. This function attempts to
885 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
886 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
887 * true. Anything else results in the return of the default value.
889 * This function uses 1 to indicate true, and 0 for false. You can check
890 * for existence by setting def to something other than 0 or 1 and
891 * examining the return value.
893 int PROFILE_GetWineIniBool(
895 char const *key_name
,
901 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
903 switch(key_value
[0]) {
924 TRACE("(\"%s\", \"%s\", %s), "
925 "[%c], ret %s.\n", section
, key_name
,
926 def
? "TRUE" : "FALSE", key_value
[0],
927 retval
? "TRUE" : "FALSE");
933 /***********************************************************************
934 * PROFILE_LoadWineIni
936 * Load the wine.ini file.
938 int PROFILE_LoadWineIni(void)
940 char buffer
[MAX_PATHNAME_LEN
];
945 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
946 if (RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine", &hKeySW
))
948 ERR("Cannot create config registry key\n" );
951 RegCloseKey( hKeySW
);
952 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config", 0, NULL
,
953 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &wine_profile_key
, NULL
))
955 ERR("Cannot create config registry key\n" );
959 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
961 if ( (Options
.configFileName
!=NULL
) && (f
= fopen(Options
.configFileName
, "r")) )
963 /* Open -config specified file */
964 lstrcpynA(PROFILE_WineIniUsed
,Options
.configFileName
,MAX_PATHNAME_LEN
);
968 if ( (p
= getenv( "WINE_INI" )) && (f
= fopen( p
, "r" )) )
970 lstrcpynA(PROFILE_WineIniUsed
,p
,MAX_PATHNAME_LEN
);
973 if ((p
= getenv( "HOME" )) != NULL
)
975 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
976 strcat( buffer
, PROFILE_WineIniName
);
977 if ((f
= fopen( buffer
, "r" )) != NULL
)
979 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
983 else WARN("could not get $HOME value for config file.\n" );
985 /* Try global file */
987 if ((f
= fopen( WINE_INI_GLOBAL
, "r" )) != NULL
)
989 lstrcpynA(PROFILE_WineIniUsed
,WINE_INI_GLOBAL
,MAX_PATHNAME_LEN
);
992 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
993 WINE_INI_GLOBAL
, PROFILE_WineIniName
);
997 PROFILE_RegistryLoad( wine_profile_key
, f
);
1003 /***********************************************************************
1004 * PROFILE_UsageWineIni
1006 * Explain the wine.ini file to those who don't read documentation.
1007 * Keep below one screenful in length so that error messages above are
1010 void PROFILE_UsageWineIni(void)
1012 MESSAGE("Perhaps you have not properly edited or created "
1013 "your Wine configuration file.\n");
1014 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL
,PROFILE_WineIniName
);
1015 MESSAGE(" or it is determined by the -config option or from\n"
1016 " the WINE_INI environment variable.\n");
1017 if (*PROFILE_WineIniUsed
)
1018 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed
);
1019 /* RTFM, so to say */
1022 /***********************************************************************
1023 * PROFILE_GetStringItem
1025 * Convenience function that turns a string 'xxx, yyy, zzz' into
1026 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1028 char* PROFILE_GetStringItem( char* start
)
1032 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1036 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1038 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1040 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1043 if( lpch
) *lpch
= '\0';
1047 /********************* API functions **********************************/
1049 /***********************************************************************
1050 * GetProfileInt16 (KERNEL.57)
1052 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1054 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1058 /***********************************************************************
1059 * GetProfileIntA (KERNEL32.264)
1061 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1063 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1066 /***********************************************************************
1067 * GetProfileIntW (KERNEL32.264)
1069 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1071 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1074 /***********************************************************************
1075 * GetProfileString16 (KERNEL.58)
1077 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1078 LPSTR buffer
, UINT16 len
)
1080 return GetPrivateProfileString16( section
, entry
, def_val
,
1081 buffer
, len
, "win.ini" );
1084 /***********************************************************************
1085 * GetProfileStringA (KERNEL32.268)
1087 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1088 LPSTR buffer
, UINT len
)
1090 return GetPrivateProfileStringA( section
, entry
, def_val
,
1091 buffer
, len
, "win.ini" );
1094 /***********************************************************************
1095 * GetProfileStringW (KERNEL32.269)
1097 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1098 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1100 return GetPrivateProfileStringW( section
, entry
, def_val
,
1101 buffer
, len
, wininiW
);
1104 /***********************************************************************
1105 * WriteProfileString16 (KERNEL.59)
1107 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1110 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1113 /***********************************************************************
1114 * WriteProfileStringA (KERNEL32.587)
1116 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1119 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1122 /***********************************************************************
1123 * WriteProfileStringW (KERNEL32.588)
1125 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1128 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1132 /***********************************************************************
1133 * GetPrivateProfileInt16 (KERNEL.127)
1135 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1136 INT16 def_val
, LPCSTR filename
)
1138 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1140 if (result
> 65535) return 65535;
1141 if (result
>= 0) return (UINT16
)result
;
1142 if (result
< -32768) return -32768;
1143 return (UINT16
)(INT16
)result
;
1146 /***********************************************************************
1147 * GetPrivateProfileIntA (KERNEL32.251)
1149 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1150 INT def_val
, LPCSTR filename
)
1156 GetPrivateProfileStringA( section
, entry
, "",
1157 buffer
, sizeof(buffer
), filename
);
1158 if (!buffer
[0]) return (UINT
)def_val
;
1159 result
= strtol( buffer
, &p
, 0 );
1160 if (p
== buffer
) return 0; /* No digits at all */
1161 return (UINT
)result
;
1164 /***********************************************************************
1165 * GetPrivateProfileIntW (KERNEL32.252)
1167 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1168 INT def_val
, LPCWSTR filename
)
1170 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1171 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1172 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1173 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1174 HeapFree( GetProcessHeap(), 0, sectionA
);
1175 HeapFree( GetProcessHeap(), 0, filenameA
);
1176 HeapFree( GetProcessHeap(), 0, entryA
);
1180 /***********************************************************************
1181 * GetPrivateProfileString16 (KERNEL.128)
1183 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1184 LPCSTR def_val
, LPSTR buffer
,
1185 UINT16 len
, LPCSTR filename
)
1187 return GetPrivateProfileStringA(section
,entry
,def_val
,buffer
,len
,filename
);
1190 /***********************************************************************
1191 * GetPrivateProfileStringA (KERNEL32.255)
1193 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1194 LPCSTR def_val
, LPSTR buffer
,
1195 UINT len
, LPCSTR filename
)
1200 filename
= "win.ini";
1202 EnterCriticalSection( &PROFILE_CritSect
);
1204 if (PROFILE_Open( filename
)) {
1205 ret
= PROFILE_GetString( section
, entry
, def_val
, buffer
, len
);
1207 lstrcpynA( buffer
, def_val
, len
);
1208 ret
= strlen( buffer
);
1211 LeaveCriticalSection( &PROFILE_CritSect
);
1216 /***********************************************************************
1217 * GetPrivateProfileStringW (KERNEL32.256)
1219 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1220 LPCWSTR def_val
, LPWSTR buffer
,
1221 UINT len
, LPCWSTR filename
)
1223 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1224 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1225 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1226 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1227 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1228 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1229 bufferA
, len
, filenameA
);
1230 lstrcpynAtoW( buffer
, bufferA
, len
);
1231 HeapFree( GetProcessHeap(), 0, sectionA
);
1232 HeapFree( GetProcessHeap(), 0, entryA
);
1233 HeapFree( GetProcessHeap(), 0, filenameA
);
1234 HeapFree( GetProcessHeap(), 0, def_valA
);
1235 HeapFree( GetProcessHeap(), 0, bufferA
);
1239 /***********************************************************************
1240 * GetPrivateProfileSection16 (KERNEL.418)
1242 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1243 UINT16 len
, LPCSTR filename
)
1245 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1248 /***********************************************************************
1249 * GetPrivateProfileSectionA (KERNEL32.255)
1251 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1252 DWORD len
, LPCSTR filename
)
1256 EnterCriticalSection( &PROFILE_CritSect
);
1258 if (PROFILE_Open( filename
))
1259 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1262 LeaveCriticalSection( &PROFILE_CritSect
);
1267 /***********************************************************************
1268 * GetPrivateProfileSectionW (KERNEL32.256)
1271 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1272 DWORD len
, LPCWSTR filename
)
1275 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1276 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1277 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1278 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1280 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1281 HeapFree( GetProcessHeap(), 0, sectionA
);
1282 HeapFree( GetProcessHeap(), 0, filenameA
);
1283 HeapFree( GetProcessHeap(), 0, bufferA
);
1287 /***********************************************************************
1288 * GetProfileSection16 (KERNEL.419)
1290 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1292 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1295 /***********************************************************************
1296 * GetProfileSectionA (KERNEL32.268)
1298 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1300 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1303 /***********************************************************************
1304 * GetProfileSectionW (KERNEL32)
1306 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1308 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1312 /***********************************************************************
1313 * WritePrivateProfileString16 (KERNEL.129)
1315 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1316 LPCSTR string
, LPCSTR filename
)
1318 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1321 /***********************************************************************
1322 * WritePrivateProfileStringA (KERNEL32.582)
1324 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1325 LPCSTR string
, LPCSTR filename
)
1329 EnterCriticalSection( &PROFILE_CritSect
);
1331 if (PROFILE_Open( filename
))
1333 if (!section
&& !entry
&& !string
)
1334 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1336 ret
= PROFILE_SetString( section
, entry
, string
);
1339 LeaveCriticalSection( &PROFILE_CritSect
);
1343 /***********************************************************************
1344 * WritePrivateProfileStringW (KERNEL32.583)
1346 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1347 LPCWSTR string
, LPCWSTR filename
)
1349 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1350 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1351 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1352 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1353 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1354 stringA
, filenameA
);
1355 HeapFree( GetProcessHeap(), 0, sectionA
);
1356 HeapFree( GetProcessHeap(), 0, entryA
);
1357 HeapFree( GetProcessHeap(), 0, stringA
);
1358 HeapFree( GetProcessHeap(), 0, filenameA
);
1362 /***********************************************************************
1363 * WritePrivateProfileSection16 (KERNEL.416)
1365 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1366 LPCSTR string
, LPCSTR filename
)
1368 return WritePrivateProfileSectionA( section
, string
, filename
);
1371 /***********************************************************************
1372 * WritePrivateProfileSectionA (KERNEL32)
1374 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1375 LPCSTR string
, LPCSTR filename
)
1380 EnterCriticalSection( &PROFILE_CritSect
);
1382 if (PROFILE_Open( filename
)) {
1383 if (!section
&& !string
&& !filename
)
1384 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1387 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1388 if((p
=strchr( buf
, '='))){
1390 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1393 HeapFree( GetProcessHeap(), 0, buf
);
1394 string
+= strlen(string
)+1;
1400 LeaveCriticalSection( &PROFILE_CritSect
);
1404 /***********************************************************************
1405 * WritePrivateProfileSectionW (KERNEL32)
1407 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1408 LPCWSTR string
, LPCWSTR filename
)
1411 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1412 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1413 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1414 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1415 HeapFree( GetProcessHeap(), 0, sectionA
);
1416 HeapFree( GetProcessHeap(), 0, stringA
);
1417 HeapFree( GetProcessHeap(), 0, filenameA
);
1421 /***********************************************************************
1422 * WriteProfileSection16 (KERNEL.417)
1424 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1426 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1429 /***********************************************************************
1430 * WriteProfileSectionA (KERNEL32.747)
1432 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1435 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1438 /***********************************************************************
1439 * WriteProfileSectionW (KERNEL32.748)
1441 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1443 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1446 /***********************************************************************
1447 * GetPrivateProfileSectionNames16 (KERNEL.143)
1449 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1454 EnterCriticalSection( &PROFILE_CritSect
);
1456 if (PROFILE_Open( filename
))
1457 ret
= PROFILE_GetSectionNames(buffer
, size
);
1459 LeaveCriticalSection( &PROFILE_CritSect
);
1465 /***********************************************************************
1466 * GetProfileSectionNames16 (KERNEL.142)
1468 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1471 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1475 /***********************************************************************
1476 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1478 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1482 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1486 /***********************************************************************
1487 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1489 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1493 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1494 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1496 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1497 lstrcpynAtoW( buffer
, bufferA
, size
);
1498 HeapFree( GetProcessHeap(), 0, bufferA
);
1499 HeapFree( GetProcessHeap(), 0, filenameA
);
1504 /***********************************************************************
1505 * GetPrivateProfileStruct16 (KERNEL.407)
1507 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1508 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1510 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1513 /***********************************************************************
1514 * GetPrivateProfileStructA (KERNEL32.370)
1516 * Should match Win95's behaviour pretty much
1518 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1519 LPVOID buf
, UINT len
, LPCSTR filename
)
1523 EnterCriticalSection( &PROFILE_CritSect
);
1525 if (PROFILE_Open( filename
)) {
1526 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1528 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1529 if (((strlen(k
->value
) - 2) / 2) == len
)
1536 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1537 /* check for invalid chars in ASCII coded hex string */
1538 for (p
=k
->value
; p
< end
; p
++)
1542 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1543 *p
, filename
, section
, key
);
1550 BOOL highnibble
= TRUE
;
1552 LPBYTE binbuf
= (LPBYTE
)buf
;
1554 end
-= 2; /* don't include checksum in output data */
1555 /* translate ASCII hex format into binary data */
1556 for (p
=k
->value
; p
< end
; p
++)
1560 (c
- 'A' + 10) : (c
- '0');
1567 *binbuf
++ = b
; /* feed binary data into output */
1568 chksum
+= b
; /* calculate checksum */
1570 highnibble
^= 1; /* toggle */
1572 /* retrieve stored checksum value */
1574 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1576 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1577 if (b
== (chksum
& 0xff)) /* checksums match ? */
1583 LeaveCriticalSection( &PROFILE_CritSect
);
1588 /***********************************************************************
1589 * GetPrivateProfileStructW (KERNEL32.543)
1591 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1592 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1594 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1595 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1596 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1597 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1599 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1601 lstrcpynAtoW( buffer
, bufferA
, len
);
1602 HeapFree( GetProcessHeap(), 0, bufferA
);
1603 HeapFree( GetProcessHeap(), 0, sectionA
);
1604 HeapFree( GetProcessHeap(), 0, keyA
);
1605 HeapFree( GetProcessHeap(), 0, filenameA
);
1612 /***********************************************************************
1613 * WritePrivateProfileStruct16 (KERNEL.406)
1615 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1616 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1618 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1621 /***********************************************************************
1622 * WritePrivateProfileStructA (KERNEL32.744)
1624 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1625 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1632 if (!section
&& !key
&& !buf
) /* flush the cache */
1633 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1635 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1636 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1638 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1639 *p
++ = hex
[*binbuf
>> 4];
1640 *p
++ = hex
[*binbuf
& 0xf];
1643 /* checksum is sum & 0xff */
1644 *p
++ = hex
[(sum
& 0xf0) >> 4];
1645 *p
++ = hex
[sum
& 0xf];
1648 EnterCriticalSection( &PROFILE_CritSect
);
1650 if (PROFILE_Open( filename
))
1651 ret
= PROFILE_SetString( section
, key
, outstring
);
1653 LeaveCriticalSection( &PROFILE_CritSect
);
1655 HeapFree( GetProcessHeap(), 0, outstring
);
1660 /***********************************************************************
1661 * WritePrivateProfileStructW (KERNEL32.544)
1663 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1664 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1666 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1667 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1668 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1669 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1671 HeapFree( GetProcessHeap(), 0, sectionA
);
1672 HeapFree( GetProcessHeap(), 0, keyA
);
1673 HeapFree( GetProcessHeap(), 0, filenameA
);
1679 /***********************************************************************
1680 * WriteOutProfiles (KERNEL.315)
1682 void WINAPI
WriteOutProfiles16(void)
1684 EnterCriticalSection( &PROFILE_CritSect
);
1685 PROFILE_FlushFile();
1686 LeaveCriticalSection( &PROFILE_CritSect
);
1689 /***********************************************************************
1690 * CloseProfileUserMapping (KERNEL.138)
1692 BOOL WINAPI
CloseProfileUserMapping(void) {
1693 FIXME("(), stub!\n");
1694 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);