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"
32 DEFAULT_DEBUG_CHANNEL(profile
);
34 typedef struct tagPROFILEKEY
38 struct tagPROFILEKEY
*next
;
41 typedef struct tagPROFILESECTION
44 struct tagPROFILEKEY
*key
;
45 struct tagPROFILESECTION
*next
;
52 PROFILESECTION
*section
;
60 #define N_CACHED_PROFILES 10
62 /* Cached profile files */
63 static PROFILE
*MRUProfile
[N_CACHED_PROFILES
]={NULL
};
65 #define CurProfile (MRUProfile[0])
67 /* wine.ini config file registry root */
68 static HKEY wine_profile_key
;
70 #define PROFILE_MAX_LINE_LEN 1024
72 /* Wine profile name in $HOME directory; must begin with slash */
73 static const char PROFILE_WineIniName
[] = "/.winerc";
75 /* Wine profile: the profile file being used */
76 static char PROFILE_WineIniUsed
[MAX_PATHNAME_LEN
] = "";
78 /* Check for comments in profile */
79 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
81 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
82 #define WINE_CONFIG_DIR "/.wine" /* config dir inside $HOME */
84 static const WCHAR wininiW
[] = { 'w','i','n','.','i','n','i',0 };
86 static CRITICAL_SECTION PROFILE_CritSect
;
88 static const char hex
[16] = "0123456789ABCDEF";
90 /***********************************************************************
91 * PROFILE_GetConfigDir
93 * Return the name of the configuration directory ($HOME/.wine)
95 const char *PROFILE_GetConfigDir(void)
100 const char *home
= getenv( "HOME" );
103 struct passwd
*pwd
= getpwuid( getuid() );
106 fprintf( stderr
, "wine: could not find your home directory\n" );
111 confdir
= xmalloc( strlen(home
) + strlen(WINE_CONFIG_DIR
) + 1 );
112 strcpy( confdir
, home
);
113 strcat( confdir
, WINE_CONFIG_DIR
);
114 mkdir( confdir
, 0755 ); /* create it just in case */
120 /***********************************************************************
123 * Copy the content of an entry into a buffer, removing quotes, and possibly
124 * translating environment variables.
126 static void PROFILE_CopyEntry( char *buffer
, const char *value
, int len
,
132 if ((*value
== '\'') || (*value
== '\"'))
134 if (value
[1] && (value
[strlen(value
)-1] == *value
)) quote
= *value
++;
139 lstrcpynA( buffer
, value
, len
);
140 if (quote
&& (len
>= strlen(value
))) buffer
[strlen(buffer
)-1] = '\0';
144 for (p
= value
; (*p
&& (len
> 1)); *buffer
++ = *p
++, len
-- )
146 if ((*p
== '$') && (p
[1] == '{'))
150 const char *p2
= strchr( p
, '}' );
151 if (!p2
) continue; /* ignore it */
152 lstrcpynA(env_val
, p
+ 2, MIN( sizeof(env_val
), (int)(p2
-p
)-1 ));
153 if ((env_p
= getenv( env_val
)) != NULL
)
155 lstrcpynA( buffer
, env_p
, len
);
156 buffer
+= strlen( buffer
);
157 len
-= strlen( buffer
);
162 if (quote
&& (len
> 1)) buffer
--;
167 /***********************************************************************
170 * Save a profile tree to a file.
172 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
176 for ( ; section
; section
= section
->next
)
178 if (section
->name
) fprintf( file
, "\r\n[%s]\r\n", section
->name
);
179 for (key
= section
->key
; key
; key
= key
->next
)
181 fprintf( file
, "%s", key
->name
);
182 if (key
->value
) fprintf( file
, "=%s", key
->value
);
183 fprintf( file
, "\r\n" );
189 /***********************************************************************
192 * Free a profile tree.
194 static void PROFILE_Free( PROFILESECTION
*section
)
196 PROFILESECTION
*next_section
;
197 PROFILEKEY
*key
, *next_key
;
199 for ( ; section
; section
= next_section
)
201 if (section
->name
) HeapFree( GetProcessHeap(), 0, section
->name
);
202 for (key
= section
->key
; key
; key
= next_key
)
204 next_key
= key
->next
;
205 if (key
->name
) HeapFree( GetProcessHeap(), 0, key
->name
);
206 if (key
->value
) HeapFree( GetProcessHeap(), 0, key
->value
);
207 HeapFree( GetProcessHeap(), 0, key
);
209 next_section
= section
->next
;
210 HeapFree( GetProcessHeap(), 0, section
);
214 static inline int PROFILE_isspace(char c
)
216 if (isspace(c
)) return 1;
217 if (c
=='\r' || c
==0x1a) return 1;
218 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
223 /***********************************************************************
226 * Load a profile tree from a file.
228 static PROFILESECTION
*PROFILE_Load( FILE *file
)
230 char buffer
[PROFILE_MAX_LINE_LEN
];
233 PROFILESECTION
*section
, *first_section
;
234 PROFILESECTION
**next_section
;
235 PROFILEKEY
*key
, *prev_key
, **next_key
;
237 first_section
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section
) );
238 first_section
->name
= NULL
;
239 first_section
->key
= NULL
;
240 first_section
->next
= NULL
;
241 next_section
= &first_section
->next
;
242 next_key
= &first_section
->key
;
245 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
249 while (*p
&& PROFILE_isspace(*p
)) p
++;
250 if (*p
== '[') /* section start */
252 if (!(p2
= strrchr( p
, ']' )))
254 WARN("Invalid section header at line %d: '%s'\n",
261 section
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section
) );
262 section
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
264 section
->next
= NULL
;
265 *next_section
= section
;
266 next_section
= §ion
->next
;
267 next_key
= §ion
->key
;
270 TRACE("New section: '%s'\n",section
->name
);
277 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
279 if ((p2
= strchr( p
, '=' )) != NULL
)
282 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
284 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
287 if(*p
|| !prev_key
|| *prev_key
->name
)
289 key
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(*key
) );
290 key
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
291 key
->value
= p2
? HEAP_strdupA( GetProcessHeap(), 0, p2
) : NULL
;
294 next_key
= &key
->next
;
297 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
300 return first_section
;
304 /***********************************************************************
305 * PROFILE_RegistryLoad
307 * Load a profile tree from a file into a registry key.
309 static DWORD
PROFILE_RegistryLoad( HKEY root
, FILE *file
)
313 char buffer
[PROFILE_MAX_LINE_LEN
];
317 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
321 while (*p
&& PROFILE_isspace(*p
)) p
++;
322 if (*p
== '[') /* section start */
324 if (!(p2
= strrchr( p
, ']' )))
326 WARN("Invalid section header at line %d: '%s'\n",
333 if (hkey
) RegCloseKey( hkey
);
334 if ((err
= RegCreateKeyExA( root
, p
, 0, NULL
, REG_OPTION_VOLATILE
,
335 KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))) return err
;
336 TRACE("New section: '%s'\n",p
);
342 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
344 if ((p2
= strchr( p
, '=' )) != NULL
)
347 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
349 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
352 if (*p
&& hkey
&& !IS_ENTRY_COMMENT(p
))
355 if ((err
= RegSetValueExA( hkey
, p
, 0, REG_SZ
, p2
, strlen(p2
)+1 )))
360 TRACE("New key: name='%s', value='%s'\n",p
,p2
);
363 if (hkey
) RegCloseKey( hkey
);
368 /***********************************************************************
369 * PROFILE_DeleteSection
371 * Delete a section from a profile tree.
373 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
377 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, name
))
379 PROFILESECTION
*to_del
= *section
;
380 *section
= to_del
->next
;
382 PROFILE_Free( to_del
);
385 section
= &(*section
)->next
;
391 /***********************************************************************
394 * Delete a key from a profile tree.
396 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
397 LPCSTR section_name
, LPCSTR key_name
)
401 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
403 PROFILEKEY
**key
= &(*section
)->key
;
406 if (!strcasecmp( (*key
)->name
, key_name
))
408 PROFILEKEY
*to_del
= *key
;
410 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
411 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
412 HeapFree( GetProcessHeap(), 0, to_del
);
418 section
= &(*section
)->next
;
424 /***********************************************************************
427 * Find a key in a profile tree, optionally creating it.
429 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
,
430 const char *section_name
,
431 const char *key_name
, int create
)
436 while (PROFILE_isspace(*section_name
)) section_name
++;
437 p
= section_name
+ strlen(section_name
) - 1;
438 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
439 seclen
= p
- section_name
+ 1;
441 while (PROFILE_isspace(*key_name
)) key_name
++;
442 p
= key_name
+ strlen(key_name
) - 1;
443 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
444 keylen
= p
- key_name
+ 1;
448 if ( ((*section
)->name
)
449 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
450 && (((*section
)->name
)[seclen
] == '\0') )
452 PROFILEKEY
**key
= &(*section
)->key
;
455 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
456 && (((*key
)->name
)[keylen
] == '\0') )
460 if (!create
) return NULL
;
461 *key
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
462 (*key
)->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
463 (*key
)->value
= NULL
;
467 section
= &(*section
)->next
;
469 if (!create
) return NULL
;
470 *section
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) );
471 (*section
)->name
= HEAP_strdupA( GetProcessHeap(), 0, section_name
);
472 (*section
)->next
= NULL
;
473 (*section
)->key
= HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
474 (*section
)->key
->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
475 (*section
)->key
->value
= NULL
;
476 (*section
)->key
->next
= NULL
;
477 return (*section
)->key
;
481 /***********************************************************************
484 * Flush the current profile to disk if changed.
486 static BOOL
PROFILE_FlushFile(void)
488 char *p
, buffer
[MAX_PATHNAME_LEN
];
489 const char *unix_name
;
495 WARN("No current profile!\n");
499 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
500 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
502 /* Try to create it in $HOME/.wine */
503 /* FIXME: this will need a more general solution */
504 strcpy( buffer
, PROFILE_GetConfigDir() );
505 p
= buffer
+ strlen(buffer
);
507 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
509 file
= fopen( buffer
, "w" );
515 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
519 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
520 PROFILE_Save( file
, CurProfile
->section
);
522 CurProfile
->changed
= FALSE
;
523 if(!stat(unix_name
,&buf
))
524 CurProfile
->mtime
=buf
.st_mtime
;
529 /***********************************************************************
530 * PROFILE_ReleaseFile
532 * Flush the current profile to disk and remove it from the cache.
534 static void PROFILE_ReleaseFile(void)
537 PROFILE_Free( CurProfile
->section
);
538 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
539 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
540 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
541 CurProfile
->changed
= FALSE
;
542 CurProfile
->section
= NULL
;
543 CurProfile
->dos_name
= NULL
;
544 CurProfile
->unix_name
= NULL
;
545 CurProfile
->filename
= NULL
;
546 CurProfile
->mtime
= 0;
550 /***********************************************************************
553 * Open a profile file, checking the cached file first.
555 static BOOL
PROFILE_Open( LPCSTR filename
)
557 DOS_FULL_NAME full_name
;
558 char buffer
[MAX_PATHNAME_LEN
];
559 char *newdos_name
, *p
;
563 PROFILE
*tempProfile
;
565 /* First time around */
568 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
570 MRUProfile
[i
]=HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
571 MRUProfile
[i
]->changed
=FALSE
;
572 MRUProfile
[i
]->section
=NULL
;
573 MRUProfile
[i
]->dos_name
=NULL
;
574 MRUProfile
[i
]->unix_name
=NULL
;
575 MRUProfile
[i
]->filename
=NULL
;
576 MRUProfile
[i
]->mtime
=0;
579 /* Check for a match */
581 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
582 strchr( filename
, ':' ))
584 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
588 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
589 strcat( buffer
, "\\" );
590 strcat( buffer
, filename
);
591 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
594 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
596 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
597 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
602 tempProfile
=MRUProfile
[i
];
604 MRUProfile
[j
]=MRUProfile
[j
-1];
605 CurProfile
=tempProfile
;
607 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
608 TRACE("(%s): already opened (mru=%d)\n",
611 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
617 /* Flush the old current profile */
620 /* Make the oldest profile the current one only in order to get rid of it */
621 if(i
==N_CACHED_PROFILES
)
623 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
624 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
625 MRUProfile
[i
]=MRUProfile
[i
-1];
626 CurProfile
=tempProfile
;
628 if(CurProfile
->filename
) PROFILE_ReleaseFile();
630 /* OK, now that CurProfile is definitely free we assign it our new file */
631 newdos_name
= HEAP_strdupA( GetProcessHeap(), 0, full_name
.short_name
);
632 CurProfile
->dos_name
= newdos_name
;
633 CurProfile
->filename
= HEAP_strdupA( GetProcessHeap(), 0, filename
);
635 /* Try to open the profile file, first in $HOME/.wine */
637 /* FIXME: this will need a more general solution */
638 strcpy( buffer
, PROFILE_GetConfigDir() );
639 p
= buffer
+ strlen(buffer
);
641 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
643 if ((file
= fopen( buffer
, "r" )))
645 TRACE("(%s): found it in %s\n",
647 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
652 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0,
653 full_name
.long_name
);
654 if ((file
= fopen( full_name
.long_name
, "r" )))
655 TRACE("(%s): found it in %s\n",
656 filename
, full_name
.long_name
);
661 CurProfile
->section
= PROFILE_Load( file
);
663 if(!stat(CurProfile
->unix_name
,&buf
))
664 CurProfile
->mtime
=buf
.st_mtime
;
668 /* Does not exist yet, we will create it in PROFILE_FlushFile */
669 WARN("profile file %s not found\n", newdos_name
);
675 /***********************************************************************
678 * Returns all keys of a section.
679 * If return_values is TRUE, also include the corresponding values.
681 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
682 LPSTR buffer
, UINT len
, BOOL handle_env
,
688 if (section
->name
&& !strcasecmp( section
->name
, section_name
))
691 for (key
= section
->key
; key
; key
= key
->next
)
694 if (!*key
->name
) continue; /* Skip empty lines */
695 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
696 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
697 len
-= strlen(buffer
) + 1;
698 buffer
+= strlen(buffer
) + 1;
699 if (return_values
&& key
->value
) {
701 PROFILE_CopyEntry ( buffer
,
702 key
->value
, len
- 1, handle_env
);
703 len
-= strlen(buffer
) + 1;
704 buffer
+= strlen(buffer
) + 1;
709 /*If either lpszSection or lpszKey is NULL and the supplied
710 destination buffer is too small to hold all the strings,
711 the last string is truncated and followed by two null characters.
712 In this case, the return value is equal to cchReturnBuffer
720 section
= section
->next
;
722 buffer
[0] = buffer
[1] = '\0';
727 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
731 PROFILESECTION
*section
;
733 for (section
= CurProfile
->section
; section
; section
= section
->next
)
735 l
= strlen(section
->name
);
740 strcpy(buf
, section
->name
);
750 /***********************************************************************
753 * Get a profile string.
755 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
756 LPCSTR def_val
, LPSTR buffer
, UINT len
)
758 PROFILEKEY
*key
= NULL
;
760 if (!def_val
) def_val
= "";
761 if (key_name
&& key_name
[0])
763 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
764 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
766 TRACE("('%s','%s','%s'): returning '%s'\n",
767 section
, key_name
, def_val
, buffer
);
768 return strlen( buffer
);
770 if (section
&& section
[0])
771 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
773 /* undocumented; both section and key_name are NULL */
774 return PROFILE_GetSectionNames(buffer
, len
);
778 /***********************************************************************
781 * Set a profile string.
783 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
786 if (!key_name
) /* Delete a whole section */
788 TRACE("('%s')\n", section_name
);
789 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
791 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
792 this is not an error on application's level.*/
794 else if (!value
) /* Delete a key */
796 TRACE("('%s','%s')\n",
797 section_name
, key_name
);
798 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
799 section_name
, key_name
);
800 return TRUE
; /* same error handling as above */
802 else /* Set the key value */
804 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
806 TRACE("('%s','%s','%s'): \n",
807 section_name
, key_name
, value
);
808 if (!key
) return FALSE
;
811 if (!strcmp( key
->value
, value
))
813 TRACE(" no change needed\n" );
814 return TRUE
; /* No change needed */
816 TRACE(" replacing '%s'\n", key
->value
);
817 HeapFree( GetProcessHeap(), 0, key
->value
);
819 else TRACE(" creating key\n" );
820 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
821 CurProfile
->changed
= TRUE
;
827 /***********************************************************************
828 * PROFILE_GetWineIniString
830 * Get a config string from the wine.ini file.
832 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
833 const char *def
, char *buffer
, int len
)
835 char tmp
[PROFILE_MAX_LINE_LEN
];
839 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
842 DWORD count
= sizeof(tmp
);
843 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
846 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
847 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
848 return strlen(buffer
);
852 /***********************************************************************
853 * PROFILE_EnumWineIniString
855 * Get a config string from the wine.ini file.
857 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
858 char *name
, int name_len
, char *buffer
, int len
)
860 char tmp
[PROFILE_MAX_LINE_LEN
];
863 DWORD count
= sizeof(tmp
);
865 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
866 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
870 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
871 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
877 /***********************************************************************
878 * PROFILE_GetWineIniInt
880 * Get a config integer from the wine.ini file.
882 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
888 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
889 if (!buffer
[0]) return def
;
890 result
= strtol( buffer
, &p
, 0 );
891 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
895 /******************************************************************************
897 * int PROFILE_GetWineIniBool(
898 * char const *section,
899 * char const *key_name,
902 * Reads a boolean value from the wine.ini file. This function attempts to
903 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
904 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
905 * true. Anything else results in the return of the default value.
907 * This function uses 1 to indicate true, and 0 for false. You can check
908 * for existence by setting def to something other than 0 or 1 and
909 * examining the return value.
911 int PROFILE_GetWineIniBool(
913 char const *key_name
,
919 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
921 switch(key_value
[0]) {
942 TRACE("(\"%s\", \"%s\", %s), "
943 "[%c], ret %s.\n", section
, key_name
,
944 def
? "TRUE" : "FALSE", key_value
[0],
945 retval
? "TRUE" : "FALSE");
951 /***********************************************************************
952 * PROFILE_LoadWineIni
954 * Load the wine.ini file.
956 int PROFILE_LoadWineIni(void)
958 char buffer
[MAX_PATHNAME_LEN
];
963 /* make sure HKLM\\Software exists as non-volatile key */
964 if (RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software", &hKeySW
))
966 ERR("Cannot create config registry key\n" );
969 RegCloseKey( hKeySW
);
970 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config", 0, NULL
,
971 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &wine_profile_key
, NULL
))
973 ERR("Cannot create config registry key\n" );
977 InitializeCriticalSection( &PROFILE_CritSect
);
978 MakeCriticalSectionGlobal( &PROFILE_CritSect
);
980 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
982 if ( (Options
.configFileName
!=NULL
) && (f
= fopen(Options
.configFileName
, "r")) )
984 /* Open -config specified file */
985 lstrcpynA(PROFILE_WineIniUsed
,Options
.configFileName
,MAX_PATHNAME_LEN
);
989 if ( (p
= getenv( "WINE_INI" )) && (f
= fopen( p
, "r" )) )
991 lstrcpynA(PROFILE_WineIniUsed
,p
,MAX_PATHNAME_LEN
);
994 if ((p
= getenv( "HOME" )) != NULL
)
996 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
997 strcat( buffer
, PROFILE_WineIniName
);
998 if ((f
= fopen( buffer
, "r" )) != NULL
)
1000 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1004 else WARN("could not get $HOME value for config file.\n" );
1006 /* Try global file */
1008 if ((f
= fopen( WINE_INI_GLOBAL
, "r" )) != NULL
)
1010 lstrcpynA(PROFILE_WineIniUsed
,WINE_INI_GLOBAL
,MAX_PATHNAME_LEN
);
1013 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1014 WINE_INI_GLOBAL
, PROFILE_WineIniName
);
1018 PROFILE_RegistryLoad( wine_profile_key
, f
);
1024 /***********************************************************************
1025 * PROFILE_UsageWineIni
1027 * Explain the wine.ini file to those who don't read documentation.
1028 * Keep below one screenful in length so that error messages above are
1031 void PROFILE_UsageWineIni(void)
1033 MESSAGE("Perhaps you have not properly edited or created "
1034 "your Wine configuration file.\n");
1035 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL
,PROFILE_WineIniName
);
1036 MESSAGE(" or it is determined by the -config option or from\n"
1037 " the WINE_INI environment variable.\n");
1038 if (*PROFILE_WineIniUsed
)
1039 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed
);
1040 /* RTFM, so to say */
1043 /***********************************************************************
1044 * PROFILE_GetStringItem
1046 * Convenience function that turns a string 'xxx, yyy, zzz' into
1047 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1049 char* PROFILE_GetStringItem( char* start
)
1053 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1057 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1059 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1061 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1064 if( lpch
) *lpch
= '\0';
1068 /********************* API functions **********************************/
1070 /***********************************************************************
1071 * GetProfileInt16 (KERNEL.57)
1073 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1075 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1079 /***********************************************************************
1080 * GetProfileInt32A (KERNEL32.264)
1082 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1084 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1087 /***********************************************************************
1088 * GetProfileInt32W (KERNEL32.264)
1090 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1092 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1095 /***********************************************************************
1096 * GetProfileString16 (KERNEL.58)
1098 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1099 LPSTR buffer
, UINT16 len
)
1101 return GetPrivateProfileString16( section
, entry
, def_val
,
1102 buffer
, len
, "win.ini" );
1105 /***********************************************************************
1106 * GetProfileString32A (KERNEL32.268)
1108 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1109 LPSTR buffer
, UINT len
)
1111 return GetPrivateProfileStringA( section
, entry
, def_val
,
1112 buffer
, len
, "win.ini" );
1115 /***********************************************************************
1116 * GetProfileString32W (KERNEL32.269)
1118 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1119 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1121 return GetPrivateProfileStringW( section
, entry
, def_val
,
1122 buffer
, len
, wininiW
);
1125 /***********************************************************************
1126 * WriteProfileString16 (KERNEL.59)
1128 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1131 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1134 /***********************************************************************
1135 * WriteProfileString32A (KERNEL32.587)
1137 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1140 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1143 /***********************************************************************
1144 * WriteProfileString32W (KERNEL32.588)
1146 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1149 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1153 /***********************************************************************
1154 * GetPrivateProfileInt16 (KERNEL.127)
1156 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1157 INT16 def_val
, LPCSTR filename
)
1159 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1161 if (result
> 65535) return 65535;
1162 if (result
>= 0) return (UINT16
)result
;
1163 if (result
< -32768) return -32768;
1164 return (UINT16
)(INT16
)result
;
1167 /***********************************************************************
1168 * GetPrivateProfileInt32A (KERNEL32.251)
1170 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1171 INT def_val
, LPCSTR filename
)
1177 GetPrivateProfileStringA( section
, entry
, "",
1178 buffer
, sizeof(buffer
), filename
);
1179 if (!buffer
[0]) return (UINT
)def_val
;
1180 result
= strtol( buffer
, &p
, 0 );
1181 if (p
== buffer
) return 0; /* No digits at all */
1182 return (UINT
)result
;
1185 /***********************************************************************
1186 * GetPrivateProfileInt32W (KERNEL32.252)
1188 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1189 INT def_val
, LPCWSTR filename
)
1191 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1192 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1193 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1194 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1195 HeapFree( GetProcessHeap(), 0, sectionA
);
1196 HeapFree( GetProcessHeap(), 0, filenameA
);
1197 HeapFree( GetProcessHeap(), 0, entryA
);
1201 /***********************************************************************
1202 * GetPrivateProfileString16 (KERNEL.128)
1204 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1205 LPCSTR def_val
, LPSTR buffer
,
1206 UINT16 len
, LPCSTR filename
)
1208 return GetPrivateProfileStringA(section
,entry
,def_val
,buffer
,len
,filename
);
1211 /***********************************************************************
1212 * GetPrivateProfileString32A (KERNEL32.255)
1214 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1215 LPCSTR def_val
, LPSTR buffer
,
1216 UINT len
, LPCSTR filename
)
1221 filename
= "win.ini";
1223 EnterCriticalSection( &PROFILE_CritSect
);
1225 if (PROFILE_Open( filename
)) {
1226 ret
= PROFILE_GetString( section
, entry
, def_val
, buffer
, len
);
1228 lstrcpynA( buffer
, def_val
, len
);
1229 ret
= strlen( buffer
);
1232 LeaveCriticalSection( &PROFILE_CritSect
);
1237 /***********************************************************************
1238 * GetPrivateProfileString32W (KERNEL32.256)
1240 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1241 LPCWSTR def_val
, LPWSTR buffer
,
1242 UINT len
, LPCWSTR filename
)
1244 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1245 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1246 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1247 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1248 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1249 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1250 bufferA
, len
, filenameA
);
1251 lstrcpynAtoW( buffer
, bufferA
, len
);
1252 HeapFree( GetProcessHeap(), 0, sectionA
);
1253 HeapFree( GetProcessHeap(), 0, entryA
);
1254 HeapFree( GetProcessHeap(), 0, filenameA
);
1255 HeapFree( GetProcessHeap(), 0, def_valA
);
1256 HeapFree( GetProcessHeap(), 0, bufferA
);
1260 /***********************************************************************
1261 * GetPrivateProfileSection16 (KERNEL.418)
1263 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1264 UINT16 len
, LPCSTR filename
)
1266 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1269 /***********************************************************************
1270 * GetPrivateProfileSection32A (KERNEL32.255)
1272 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1273 DWORD len
, LPCSTR filename
)
1277 EnterCriticalSection( &PROFILE_CritSect
);
1279 if (PROFILE_Open( filename
))
1280 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1283 LeaveCriticalSection( &PROFILE_CritSect
);
1288 /***********************************************************************
1289 * GetPrivateProfileSection32W (KERNEL32.256)
1292 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1293 DWORD len
, LPCWSTR filename
)
1296 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1297 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1298 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1299 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1301 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1302 HeapFree( GetProcessHeap(), 0, sectionA
);
1303 HeapFree( GetProcessHeap(), 0, filenameA
);
1304 HeapFree( GetProcessHeap(), 0, bufferA
);
1308 /***********************************************************************
1309 * GetProfileSection16 (KERNEL.419)
1311 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1313 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1316 /***********************************************************************
1317 * GetProfileSection32A (KERNEL32.268)
1319 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1321 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1324 /***********************************************************************
1325 * GetProfileSection32W (KERNEL32)
1327 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1329 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1333 /***********************************************************************
1334 * WritePrivateProfileString16 (KERNEL.129)
1336 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1337 LPCSTR string
, LPCSTR filename
)
1339 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1342 /***********************************************************************
1343 * WritePrivateProfileString32A (KERNEL32.582)
1345 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1346 LPCSTR string
, LPCSTR filename
)
1350 EnterCriticalSection( &PROFILE_CritSect
);
1352 if (PROFILE_Open( filename
))
1354 if (!section
&& !entry
&& !string
)
1355 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1357 ret
= PROFILE_SetString( section
, entry
, string
);
1360 LeaveCriticalSection( &PROFILE_CritSect
);
1364 /***********************************************************************
1365 * WritePrivateProfileString32W (KERNEL32.583)
1367 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1368 LPCWSTR string
, LPCWSTR filename
)
1370 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1371 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1372 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1373 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1374 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1375 stringA
, filenameA
);
1376 HeapFree( GetProcessHeap(), 0, sectionA
);
1377 HeapFree( GetProcessHeap(), 0, entryA
);
1378 HeapFree( GetProcessHeap(), 0, stringA
);
1379 HeapFree( GetProcessHeap(), 0, filenameA
);
1383 /***********************************************************************
1384 * WritePrivateProfileSection16 (KERNEL.416)
1386 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1387 LPCSTR string
, LPCSTR filename
)
1389 return WritePrivateProfileSectionA( section
, string
, filename
);
1392 /***********************************************************************
1393 * WritePrivateProfileSectionA (KERNEL32)
1395 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1396 LPCSTR string
, LPCSTR filename
)
1401 EnterCriticalSection( &PROFILE_CritSect
);
1403 if (PROFILE_Open( filename
)) {
1404 if (!section
&& !string
&& !filename
)
1405 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1408 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1409 if((p
=strchr( buf
, '='))){
1411 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1414 HeapFree( GetProcessHeap(), 0, buf
);
1415 string
+= strlen(string
)+1;
1421 LeaveCriticalSection( &PROFILE_CritSect
);
1425 /***********************************************************************
1426 * WritePrivateProfileSection32W (KERNEL32)
1428 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1429 LPCWSTR string
, LPCWSTR filename
)
1432 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1433 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1434 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1435 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1436 HeapFree( GetProcessHeap(), 0, sectionA
);
1437 HeapFree( GetProcessHeap(), 0, stringA
);
1438 HeapFree( GetProcessHeap(), 0, filenameA
);
1442 /***********************************************************************
1443 * WriteProfileSection16 (KERNEL.417)
1445 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1447 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1450 /***********************************************************************
1451 * WriteProfileSection32A (KERNEL32.747)
1453 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1456 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1459 /***********************************************************************
1460 * WriteProfileSection32W (KERNEL32.748)
1462 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1464 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1467 /***********************************************************************
1468 * GetPrivateProfileSectionNames16 (KERNEL.143)
1470 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1475 EnterCriticalSection( &PROFILE_CritSect
);
1477 if (PROFILE_Open( filename
))
1478 ret
= PROFILE_GetSectionNames(buffer
, size
);
1480 LeaveCriticalSection( &PROFILE_CritSect
);
1486 /***********************************************************************
1487 * GetProfileSectionNames16 (KERNEL.142)
1489 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1492 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1496 /***********************************************************************
1497 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1499 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1503 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1507 /***********************************************************************
1508 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1510 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1514 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1515 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1517 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1518 lstrcpynAtoW( buffer
, bufferA
, size
);
1519 HeapFree( GetProcessHeap(), 0, bufferA
);
1520 HeapFree( GetProcessHeap(), 0, filenameA
);
1525 /***********************************************************************
1526 * GetPrivateProfileStruct16 (KERNEL.407)
1528 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1529 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1531 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1534 /***********************************************************************
1535 * GetPrivateProfileStruct32A (KERNEL32.370)
1537 * Should match Win95's behaviour pretty much
1539 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1540 LPVOID buf
, UINT len
, LPCSTR filename
)
1544 EnterCriticalSection( &PROFILE_CritSect
);
1546 if (PROFILE_Open( filename
)) {
1547 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1549 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1550 if (((strlen(k
->value
) - 2) / 2) == len
)
1557 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1558 /* check for invalid chars in ASCII coded hex string */
1559 for (p
=k
->value
; p
< end
; p
++)
1563 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1564 *p
, filename
, section
, key
);
1571 BOOL highnibble
= TRUE
;
1573 LPBYTE binbuf
= (LPBYTE
)buf
;
1575 end
-= 2; /* don't include checksum in output data */
1576 /* translate ASCII hex format into binary data */
1577 for (p
=k
->value
; p
< end
; p
++)
1581 (c
- 'A' + 10) : (c
- '0');
1588 *binbuf
++ = b
; /* feed binary data into output */
1589 chksum
+= b
; /* calculate checksum */
1591 highnibble
^= 1; /* toggle */
1593 /* retrieve stored checksum value */
1595 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1597 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1598 if (b
== (chksum
& 0xff)) /* checksums match ? */
1604 LeaveCriticalSection( &PROFILE_CritSect
);
1609 /***********************************************************************
1610 * GetPrivateProfileStruct32W (KERNEL32.543)
1612 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1613 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1615 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1616 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1617 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1618 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1620 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1622 lstrcpynAtoW( buffer
, bufferA
, len
);
1623 HeapFree( GetProcessHeap(), 0, bufferA
);
1624 HeapFree( GetProcessHeap(), 0, sectionA
);
1625 HeapFree( GetProcessHeap(), 0, keyA
);
1626 HeapFree( GetProcessHeap(), 0, filenameA
);
1633 /***********************************************************************
1634 * WritePrivateProfileStruct16 (KERNEL.406)
1636 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1637 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1639 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1642 /***********************************************************************
1643 * WritePrivateProfileStruct32A (KERNEL32.744)
1645 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1646 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1653 if (!section
&& !key
&& !buf
) /* flush the cache */
1654 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1656 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1657 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1659 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1660 *p
++ = hex
[*binbuf
>> 4];
1661 *p
++ = hex
[*binbuf
& 0xf];
1664 /* checksum is sum & 0xff */
1665 *p
++ = hex
[(sum
& 0xf0) >> 4];
1666 *p
++ = hex
[sum
& 0xf];
1669 EnterCriticalSection( &PROFILE_CritSect
);
1671 if (PROFILE_Open( filename
))
1672 ret
= PROFILE_SetString( section
, key
, outstring
);
1674 LeaveCriticalSection( &PROFILE_CritSect
);
1676 HeapFree( GetProcessHeap(), 0, outstring
);
1681 /***********************************************************************
1682 * WritePrivateProfileStruct32W (KERNEL32.544)
1684 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1685 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1687 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1688 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1689 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1690 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1692 HeapFree( GetProcessHeap(), 0, sectionA
);
1693 HeapFree( GetProcessHeap(), 0, keyA
);
1694 HeapFree( GetProcessHeap(), 0, filenameA
);
1700 /***********************************************************************
1701 * WriteOutProfiles (KERNEL.315)
1703 void WINAPI
WriteOutProfiles16(void)
1705 EnterCriticalSection( &PROFILE_CritSect
);
1706 PROFILE_FlushFile();
1707 LeaveCriticalSection( &PROFILE_CritSect
);
1710 /***********************************************************************
1711 * CloseProfileUserMapping (KERNEL.138)
1713 BOOL WINAPI
CloseProfileUserMapping(void) {
1714 FIXME("(), stub!\n");
1715 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);