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 /***********************************************************************
396 * PROFILE_DeleteAllKeys
398 * Delete all keys from a profile tree.
400 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
402 PROFILESECTION
**section
= &CurProfile
->section
;
405 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
407 PROFILEKEY
**key
= &(*section
)->key
;
410 PROFILEKEY
*to_del
= *key
;
412 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
413 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
414 HeapFree( GetProcessHeap(), 0, to_del
);
415 CurProfile
->changed
=TRUE
;
418 section
= &(*section
)->next
;
423 /***********************************************************************
426 * Find a key in a profile tree, optionally creating it.
428 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
,
429 const char *section_name
,
430 const char *key_name
, int create
)
435 while (PROFILE_isspace(*section_name
)) section_name
++;
436 p
= section_name
+ strlen(section_name
) - 1;
437 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
438 seclen
= p
- section_name
+ 1;
440 while (PROFILE_isspace(*key_name
)) key_name
++;
441 p
= key_name
+ strlen(key_name
) - 1;
442 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
443 keylen
= p
- key_name
+ 1;
447 if ( ((*section
)->name
)
448 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
449 && (((*section
)->name
)[seclen
] == '\0') )
451 PROFILEKEY
**key
= &(*section
)->key
;
454 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
455 && (((*key
)->name
)[keylen
] == '\0') )
459 if (!create
) return NULL
;
460 *key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
461 if(*key
== NULL
) return NULL
;
462 (*key
)->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
463 (*key
)->value
= NULL
;
467 section
= &(*section
)->next
;
469 if (!create
) return NULL
;
470 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) );
471 if(*section
== NULL
) return NULL
;
472 (*section
)->name
= HEAP_strdupA( GetProcessHeap(), 0, section_name
);
473 (*section
)->next
= NULL
;
474 (*section
)->key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
475 if((*section
)->key
== NULL
)
477 HeapFree(GetProcessHeap(), 0, *section
);
480 (*section
)->key
->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
481 (*section
)->key
->value
= NULL
;
482 (*section
)->key
->next
= NULL
;
483 return (*section
)->key
;
487 /***********************************************************************
490 * Flush the current profile to disk if changed.
492 static BOOL
PROFILE_FlushFile(void)
494 char *p
, buffer
[MAX_PATHNAME_LEN
];
495 const char *unix_name
;
501 WARN("No current profile!\n");
505 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
506 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
508 /* Try to create it in $HOME/.wine */
509 /* FIXME: this will need a more general solution */
510 strcpy( buffer
, get_config_dir() );
511 p
= buffer
+ strlen(buffer
);
513 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
515 file
= fopen( buffer
, "w" );
521 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
525 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
526 PROFILE_Save( file
, CurProfile
->section
);
528 CurProfile
->changed
= FALSE
;
529 if(!stat(unix_name
,&buf
))
530 CurProfile
->mtime
=buf
.st_mtime
;
535 /***********************************************************************
536 * PROFILE_ReleaseFile
538 * Flush the current profile to disk and remove it from the cache.
540 static void PROFILE_ReleaseFile(void)
543 PROFILE_Free( CurProfile
->section
);
544 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
545 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
546 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
547 CurProfile
->changed
= FALSE
;
548 CurProfile
->section
= NULL
;
549 CurProfile
->dos_name
= NULL
;
550 CurProfile
->unix_name
= NULL
;
551 CurProfile
->filename
= NULL
;
552 CurProfile
->mtime
= 0;
556 /***********************************************************************
559 * Open a profile file, checking the cached file first.
561 static BOOL
PROFILE_Open( LPCSTR filename
)
563 DOS_FULL_NAME full_name
;
564 char buffer
[MAX_PATHNAME_LEN
];
565 char *newdos_name
, *p
;
569 PROFILE
*tempProfile
;
571 /* First time around */
574 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
576 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
577 if(MRUProfile
[i
] == NULL
) break;
578 MRUProfile
[i
]->changed
=FALSE
;
579 MRUProfile
[i
]->section
=NULL
;
580 MRUProfile
[i
]->dos_name
=NULL
;
581 MRUProfile
[i
]->unix_name
=NULL
;
582 MRUProfile
[i
]->filename
=NULL
;
583 MRUProfile
[i
]->mtime
=0;
586 /* Check for a match */
588 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
589 strchr( filename
, ':' ))
591 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
595 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
596 strcat( buffer
, "\\" );
597 strcat( buffer
, filename
);
598 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
601 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
603 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
604 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
609 tempProfile
=MRUProfile
[i
];
611 MRUProfile
[j
]=MRUProfile
[j
-1];
612 CurProfile
=tempProfile
;
614 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
615 TRACE("(%s): already opened (mru=%d)\n",
618 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
624 /* Flush the old current profile */
627 /* Make the oldest profile the current one only in order to get rid of it */
628 if(i
==N_CACHED_PROFILES
)
630 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
631 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
632 MRUProfile
[i
]=MRUProfile
[i
-1];
633 CurProfile
=tempProfile
;
635 if(CurProfile
->filename
) PROFILE_ReleaseFile();
637 /* OK, now that CurProfile is definitely free we assign it our new file */
638 newdos_name
= HEAP_strdupA( GetProcessHeap(), 0, full_name
.short_name
);
639 CurProfile
->dos_name
= newdos_name
;
640 CurProfile
->filename
= HEAP_strdupA( GetProcessHeap(), 0, filename
);
642 /* Try to open the profile file, first in $HOME/.wine */
644 /* FIXME: this will need a more general solution */
645 strcpy( buffer
, get_config_dir() );
646 p
= buffer
+ strlen(buffer
);
648 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
650 if ((file
= fopen( buffer
, "r" )))
652 TRACE("(%s): found it in %s\n",
654 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
659 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0,
660 full_name
.long_name
);
661 if ((file
= fopen( full_name
.long_name
, "r" )))
662 TRACE("(%s): found it in %s\n",
663 filename
, full_name
.long_name
);
668 CurProfile
->section
= PROFILE_Load( file
);
670 if(!stat(CurProfile
->unix_name
,&buf
))
671 CurProfile
->mtime
=buf
.st_mtime
;
675 /* Does not exist yet, we will create it in PROFILE_FlushFile */
676 WARN("profile file %s not found\n", newdos_name
);
682 /***********************************************************************
685 * Returns all keys of a section.
686 * If return_values is TRUE, also include the corresponding values.
688 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
689 LPSTR buffer
, UINT len
, BOOL handle_env
,
695 if (section
->name
&& !strcasecmp( section
->name
, section_name
))
698 for (key
= section
->key
; key
; key
= key
->next
)
701 if (!*key
->name
) continue; /* Skip empty lines */
702 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
703 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
704 len
-= strlen(buffer
) + 1;
705 buffer
+= strlen(buffer
) + 1;
706 if (return_values
&& key
->value
) {
708 PROFILE_CopyEntry ( buffer
,
709 key
->value
, len
- 1, handle_env
);
710 len
-= strlen(buffer
) + 1;
711 buffer
+= strlen(buffer
) + 1;
716 /*If either lpszSection or lpszKey is NULL and the supplied
717 destination buffer is too small to hold all the strings,
718 the last string is truncated and followed by two null characters.
719 In this case, the return value is equal to cchReturnBuffer
727 section
= section
->next
;
729 buffer
[0] = buffer
[1] = '\0';
734 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
738 PROFILESECTION
*section
;
740 for (section
= CurProfile
->section
; section
; section
= section
->next
)
742 l
= strlen(section
->name
);
747 strcpy(buf
, section
->name
);
757 /***********************************************************************
760 * Get a profile string.
762 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
763 LPCSTR def_val
, LPSTR buffer
, UINT len
)
765 PROFILEKEY
*key
= NULL
;
767 if (!def_val
) def_val
= "";
768 if (key_name
&& key_name
[0])
770 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
771 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
773 TRACE("('%s','%s','%s'): returning '%s'\n",
774 section
, key_name
, def_val
, buffer
);
775 return strlen( buffer
);
777 if (key_name
&& !(key_name
[0]))
778 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
780 if (section
&& section
[0])
781 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
783 /* undocumented; both section and key_name are NULL */
784 return PROFILE_GetSectionNames(buffer
, len
);
788 /***********************************************************************
791 * Set a profile string.
793 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
796 if (!key_name
) /* Delete a whole section */
798 TRACE("('%s')\n", section_name
);
799 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
801 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
802 this is not an error on application's level.*/
804 else if (!value
) /* Delete a key */
806 TRACE("('%s','%s')\n",
807 section_name
, key_name
);
808 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
809 section_name
, key_name
);
810 return TRUE
; /* same error handling as above */
812 else /* Set the key value */
814 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
816 TRACE("('%s','%s','%s'): \n",
817 section_name
, key_name
, value
);
818 if (!key
) return FALSE
;
821 /* strip the leading spaces. We can safely strip \n\r and
822 * friends too, they should not happen here anyway. */
823 while (PROFILE_isspace(*value
)) value
++;
825 if (!strcmp( key
->value
, value
))
827 TRACE(" no change needed\n" );
828 return TRUE
; /* No change needed */
830 TRACE(" replacing '%s'\n", key
->value
);
831 HeapFree( GetProcessHeap(), 0, key
->value
);
833 else TRACE(" creating key\n" );
834 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
835 CurProfile
->changed
= TRUE
;
841 /***********************************************************************
842 * PROFILE_GetWineIniString
844 * Get a config string from the wine.ini file.
846 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
847 const char *def
, char *buffer
, int len
)
849 char tmp
[PROFILE_MAX_LINE_LEN
];
853 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
856 DWORD count
= sizeof(tmp
);
857 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
860 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
861 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
862 return strlen(buffer
);
866 /***********************************************************************
867 * PROFILE_EnumWineIniString
869 * Get a config string from the wine.ini file.
871 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
872 char *name
, int name_len
, char *buffer
, int len
)
874 char tmp
[PROFILE_MAX_LINE_LEN
];
877 DWORD count
= sizeof(tmp
);
879 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
880 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
884 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
885 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
891 /***********************************************************************
892 * PROFILE_GetWineIniInt
894 * Get a config integer from the wine.ini file.
896 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
902 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
903 if (!buffer
[0]) return def
;
904 result
= strtol( buffer
, &p
, 0 );
905 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
909 /******************************************************************************
911 * int PROFILE_GetWineIniBool(
912 * char const *section,
913 * char const *key_name,
916 * Reads a boolean value from the wine.ini file. This function attempts to
917 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
918 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
919 * true. Anything else results in the return of the default value.
921 * This function uses 1 to indicate true, and 0 for false. You can check
922 * for existence by setting def to something other than 0 or 1 and
923 * examining the return value.
925 int PROFILE_GetWineIniBool(
927 char const *key_name
,
933 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
935 switch(key_value
[0]) {
956 TRACE("(\"%s\", \"%s\", %s), "
957 "[%c], ret %s.\n", section
, key_name
,
958 def
? "TRUE" : "FALSE", key_value
[0],
959 retval
? "TRUE" : "FALSE");
965 /***********************************************************************
966 * PROFILE_LoadWineIni
968 * Load the wine.ini file.
970 int PROFILE_LoadWineIni(void)
972 char buffer
[MAX_PATHNAME_LEN
];
977 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
978 if (RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine", &hKeySW
))
980 ERR("Cannot create config registry key\n" );
983 RegCloseKey( hKeySW
);
984 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config", 0, NULL
,
985 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &wine_profile_key
, NULL
))
987 ERR("Cannot create config registry key\n" );
991 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
993 if ( (Options
.configFileName
!=NULL
) && (f
= fopen(Options
.configFileName
, "r")) )
995 /* Open -config specified file */
996 lstrcpynA(PROFILE_WineIniUsed
,Options
.configFileName
,MAX_PATHNAME_LEN
);
1000 if ( (p
= getenv( "WINE_INI" )) && (f
= fopen( p
, "r" )) )
1002 lstrcpynA(PROFILE_WineIniUsed
,p
,MAX_PATHNAME_LEN
);
1005 if ((p
= getenv( "HOME" )) != NULL
)
1007 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1008 strcat( buffer
, PROFILE_WineIniName
);
1009 if ((f
= fopen( buffer
, "r" )) != NULL
)
1011 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1015 else WARN("could not get $HOME value for config file.\n" );
1017 /* Try global file */
1019 if ((f
= fopen( WINE_INI_GLOBAL
, "r" )) != NULL
)
1021 lstrcpynA(PROFILE_WineIniUsed
,WINE_INI_GLOBAL
,MAX_PATHNAME_LEN
);
1024 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1025 WINE_INI_GLOBAL
, PROFILE_WineIniName
);
1029 PROFILE_RegistryLoad( wine_profile_key
, f
);
1035 /***********************************************************************
1036 * PROFILE_UsageWineIni
1038 * Explain the wine.ini file to those who don't read documentation.
1039 * Keep below one screenful in length so that error messages above are
1042 void PROFILE_UsageWineIni(void)
1044 MESSAGE("Perhaps you have not properly edited or created "
1045 "your Wine configuration file.\n");
1046 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL
,PROFILE_WineIniName
);
1047 MESSAGE(" or it is determined by the -config option or from\n"
1048 " the WINE_INI environment variable.\n");
1049 if (*PROFILE_WineIniUsed
)
1050 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed
);
1051 /* RTFM, so to say */
1054 /***********************************************************************
1055 * PROFILE_GetStringItem
1057 * Convenience function that turns a string 'xxx, yyy, zzz' into
1058 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1060 char* PROFILE_GetStringItem( char* start
)
1064 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1068 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1070 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1072 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1075 if( lpch
) *lpch
= '\0';
1079 /********************* API functions **********************************/
1081 /***********************************************************************
1082 * GetProfileInt16 (KERNEL.57)
1084 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1086 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1090 /***********************************************************************
1091 * GetProfileIntA (KERNEL32.264)
1093 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1095 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1098 /***********************************************************************
1099 * GetProfileIntW (KERNEL32.264)
1101 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1103 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1106 /***********************************************************************
1107 * GetProfileString16 (KERNEL.58)
1109 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1110 LPSTR buffer
, UINT16 len
)
1112 return GetPrivateProfileString16( section
, entry
, def_val
,
1113 buffer
, len
, "win.ini" );
1116 /***********************************************************************
1117 * GetProfileStringA (KERNEL32.268)
1119 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1120 LPSTR buffer
, UINT len
)
1122 return GetPrivateProfileStringA( section
, entry
, def_val
,
1123 buffer
, len
, "win.ini" );
1126 /***********************************************************************
1127 * GetProfileStringW (KERNEL32.269)
1129 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1130 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1132 return GetPrivateProfileStringW( section
, entry
, def_val
,
1133 buffer
, len
, wininiW
);
1136 /***********************************************************************
1137 * WriteProfileString16 (KERNEL.59)
1139 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1142 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1145 /***********************************************************************
1146 * WriteProfileStringA (KERNEL32.587)
1148 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1151 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1154 /***********************************************************************
1155 * WriteProfileStringW (KERNEL32.588)
1157 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1160 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1164 /***********************************************************************
1165 * GetPrivateProfileInt16 (KERNEL.127)
1167 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1168 INT16 def_val
, LPCSTR filename
)
1170 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1172 if (result
> 65535) return 65535;
1173 if (result
>= 0) return (UINT16
)result
;
1174 if (result
< -32768) return -32768;
1175 return (UINT16
)(INT16
)result
;
1178 /***********************************************************************
1179 * GetPrivateProfileIntA (KERNEL32.251)
1181 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1182 INT def_val
, LPCSTR filename
)
1188 GetPrivateProfileStringA( section
, entry
, "",
1189 buffer
, sizeof(buffer
), filename
);
1190 if (!buffer
[0]) return (UINT
)def_val
;
1191 result
= strtol( buffer
, &p
, 0 );
1192 if (p
== buffer
) return 0; /* No digits at all */
1193 return (UINT
)result
;
1196 /***********************************************************************
1197 * GetPrivateProfileIntW (KERNEL32.252)
1199 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1200 INT def_val
, LPCWSTR filename
)
1202 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1203 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1204 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1205 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1206 HeapFree( GetProcessHeap(), 0, sectionA
);
1207 HeapFree( GetProcessHeap(), 0, filenameA
);
1208 HeapFree( GetProcessHeap(), 0, entryA
);
1212 /***********************************************************************
1213 * GetPrivateProfileString16 (KERNEL.128)
1215 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1216 LPCSTR def_val
, LPSTR buffer
,
1217 UINT16 len
, LPCSTR filename
)
1219 return GetPrivateProfileStringA(section
,entry
,def_val
,buffer
,len
,filename
);
1222 /***********************************************************************
1223 * GetPrivateProfileStringA (KERNEL32.255)
1225 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1226 LPCSTR def_val
, LPSTR buffer
,
1227 UINT len
, LPCSTR filename
)
1232 filename
= "win.ini";
1234 EnterCriticalSection( &PROFILE_CritSect
);
1236 if (PROFILE_Open( filename
)) {
1237 ret
= PROFILE_GetString( section
, entry
, def_val
, buffer
, len
);
1239 lstrcpynA( buffer
, def_val
, len
);
1240 ret
= strlen( buffer
);
1243 LeaveCriticalSection( &PROFILE_CritSect
);
1248 /***********************************************************************
1249 * GetPrivateProfileStringW (KERNEL32.256)
1251 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1252 LPCWSTR def_val
, LPWSTR buffer
,
1253 UINT len
, LPCWSTR filename
)
1255 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1256 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1257 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1258 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1259 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1260 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1261 bufferA
, len
, filenameA
);
1262 lstrcpynAtoW( buffer
, bufferA
, len
);
1263 HeapFree( GetProcessHeap(), 0, sectionA
);
1264 HeapFree( GetProcessHeap(), 0, entryA
);
1265 HeapFree( GetProcessHeap(), 0, filenameA
);
1266 HeapFree( GetProcessHeap(), 0, def_valA
);
1267 HeapFree( GetProcessHeap(), 0, bufferA
);
1271 /***********************************************************************
1272 * GetPrivateProfileSection16 (KERNEL.418)
1274 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1275 UINT16 len
, LPCSTR filename
)
1277 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1280 /***********************************************************************
1281 * GetPrivateProfileSectionA (KERNEL32.255)
1283 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1284 DWORD len
, LPCSTR filename
)
1288 EnterCriticalSection( &PROFILE_CritSect
);
1290 if (PROFILE_Open( filename
))
1291 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1294 LeaveCriticalSection( &PROFILE_CritSect
);
1299 /***********************************************************************
1300 * GetPrivateProfileSectionW (KERNEL32.256)
1303 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1304 DWORD len
, LPCWSTR filename
)
1307 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1308 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1309 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1310 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1312 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1313 HeapFree( GetProcessHeap(), 0, sectionA
);
1314 HeapFree( GetProcessHeap(), 0, filenameA
);
1315 HeapFree( GetProcessHeap(), 0, bufferA
);
1319 /***********************************************************************
1320 * GetProfileSection16 (KERNEL.419)
1322 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1324 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1327 /***********************************************************************
1328 * GetProfileSectionA (KERNEL32.268)
1330 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1332 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1335 /***********************************************************************
1336 * GetProfileSectionW (KERNEL32)
1338 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1340 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1344 /***********************************************************************
1345 * WritePrivateProfileString16 (KERNEL.129)
1347 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1348 LPCSTR string
, LPCSTR filename
)
1350 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1353 /***********************************************************************
1354 * WritePrivateProfileStringA (KERNEL32.582)
1356 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1357 LPCSTR string
, LPCSTR filename
)
1361 EnterCriticalSection( &PROFILE_CritSect
);
1363 if (PROFILE_Open( filename
))
1365 if (!section
&& !entry
&& !string
)
1366 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1368 ret
= PROFILE_SetString( section
, entry
, string
);
1371 LeaveCriticalSection( &PROFILE_CritSect
);
1375 /***********************************************************************
1376 * WritePrivateProfileStringW (KERNEL32.583)
1378 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1379 LPCWSTR string
, LPCWSTR filename
)
1381 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1382 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1383 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1384 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1385 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1386 stringA
, filenameA
);
1387 HeapFree( GetProcessHeap(), 0, sectionA
);
1388 HeapFree( GetProcessHeap(), 0, entryA
);
1389 HeapFree( GetProcessHeap(), 0, stringA
);
1390 HeapFree( GetProcessHeap(), 0, filenameA
);
1394 /***********************************************************************
1395 * WritePrivateProfileSection16 (KERNEL.416)
1397 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1398 LPCSTR string
, LPCSTR filename
)
1400 return WritePrivateProfileSectionA( section
, string
, filename
);
1403 /***********************************************************************
1404 * WritePrivateProfileSectionA (KERNEL32)
1406 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1407 LPCSTR string
, LPCSTR filename
)
1412 EnterCriticalSection( &PROFILE_CritSect
);
1414 if (PROFILE_Open( filename
)) {
1415 if (!section
&& !string
&& !filename
)
1416 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1417 else if (!string
) /* delete the named section*/
1418 ret
= PROFILE_SetString(section
,NULL
,NULL
);
1420 PROFILE_DeleteAllKeys(section
);
1423 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1424 if((p
=strchr( buf
, '='))){
1426 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1429 HeapFree( GetProcessHeap(), 0, buf
);
1430 string
+= strlen(string
)+1;
1436 LeaveCriticalSection( &PROFILE_CritSect
);
1440 /***********************************************************************
1441 * WritePrivateProfileSectionW (KERNEL32)
1443 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1444 LPCWSTR string
, LPCWSTR filename
)
1447 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1448 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1449 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1450 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1451 HeapFree( GetProcessHeap(), 0, sectionA
);
1452 HeapFree( GetProcessHeap(), 0, stringA
);
1453 HeapFree( GetProcessHeap(), 0, filenameA
);
1457 /***********************************************************************
1458 * WriteProfileSection16 (KERNEL.417)
1460 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1462 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1465 /***********************************************************************
1466 * WriteProfileSectionA (KERNEL32.747)
1468 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1471 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1474 /***********************************************************************
1475 * WriteProfileSectionW (KERNEL32.748)
1477 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1479 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1482 /***********************************************************************
1483 * GetPrivateProfileSectionNames16 (KERNEL.143)
1485 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1490 EnterCriticalSection( &PROFILE_CritSect
);
1492 if (PROFILE_Open( filename
))
1493 ret
= PROFILE_GetSectionNames(buffer
, size
);
1495 LeaveCriticalSection( &PROFILE_CritSect
);
1501 /***********************************************************************
1502 * GetProfileSectionNames16 (KERNEL.142)
1504 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1507 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1511 /***********************************************************************
1512 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1514 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1518 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1522 /***********************************************************************
1523 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1525 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1529 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1530 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1532 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1533 lstrcpynAtoW( buffer
, bufferA
, size
);
1534 HeapFree( GetProcessHeap(), 0, bufferA
);
1535 HeapFree( GetProcessHeap(), 0, filenameA
);
1540 /***********************************************************************
1541 * GetPrivateProfileStruct16 (KERNEL.407)
1543 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1544 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1546 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1549 /***********************************************************************
1550 * GetPrivateProfileStructA (KERNEL32.370)
1552 * Should match Win95's behaviour pretty much
1554 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1555 LPVOID buf
, UINT len
, LPCSTR filename
)
1559 EnterCriticalSection( &PROFILE_CritSect
);
1561 if (PROFILE_Open( filename
)) {
1562 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1564 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1565 if (((strlen(k
->value
) - 2) / 2) == len
)
1572 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1573 /* check for invalid chars in ASCII coded hex string */
1574 for (p
=k
->value
; p
< end
; p
++)
1578 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1579 *p
, filename
, section
, key
);
1586 BOOL highnibble
= TRUE
;
1588 LPBYTE binbuf
= (LPBYTE
)buf
;
1590 end
-= 2; /* don't include checksum in output data */
1591 /* translate ASCII hex format into binary data */
1592 for (p
=k
->value
; p
< end
; p
++)
1596 (c
- 'A' + 10) : (c
- '0');
1603 *binbuf
++ = b
; /* feed binary data into output */
1604 chksum
+= b
; /* calculate checksum */
1606 highnibble
^= 1; /* toggle */
1608 /* retrieve stored checksum value */
1610 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1612 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1613 if (b
== (chksum
& 0xff)) /* checksums match ? */
1619 LeaveCriticalSection( &PROFILE_CritSect
);
1624 /***********************************************************************
1625 * GetPrivateProfileStructW (KERNEL32.543)
1627 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1628 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1630 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1631 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1632 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1633 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1635 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1637 lstrcpynAtoW( buffer
, bufferA
, len
);
1638 HeapFree( GetProcessHeap(), 0, bufferA
);
1639 HeapFree( GetProcessHeap(), 0, sectionA
);
1640 HeapFree( GetProcessHeap(), 0, keyA
);
1641 HeapFree( GetProcessHeap(), 0, filenameA
);
1648 /***********************************************************************
1649 * WritePrivateProfileStruct16 (KERNEL.406)
1651 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1652 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1654 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1657 /***********************************************************************
1658 * WritePrivateProfileStructA (KERNEL32.744)
1660 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1661 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1668 if (!section
&& !key
&& !buf
) /* flush the cache */
1669 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1671 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1672 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1674 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1675 *p
++ = hex
[*binbuf
>> 4];
1676 *p
++ = hex
[*binbuf
& 0xf];
1679 /* checksum is sum & 0xff */
1680 *p
++ = hex
[(sum
& 0xf0) >> 4];
1681 *p
++ = hex
[sum
& 0xf];
1684 EnterCriticalSection( &PROFILE_CritSect
);
1686 if (PROFILE_Open( filename
))
1687 ret
= PROFILE_SetString( section
, key
, outstring
);
1689 LeaveCriticalSection( &PROFILE_CritSect
);
1691 HeapFree( GetProcessHeap(), 0, outstring
);
1696 /***********************************************************************
1697 * WritePrivateProfileStructW (KERNEL32.544)
1699 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1700 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1702 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1703 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1704 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1705 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1707 HeapFree( GetProcessHeap(), 0, sectionA
);
1708 HeapFree( GetProcessHeap(), 0, keyA
);
1709 HeapFree( GetProcessHeap(), 0, filenameA
);
1715 /***********************************************************************
1716 * WriteOutProfiles (KERNEL.315)
1718 void WINAPI
WriteOutProfiles16(void)
1720 EnterCriticalSection( &PROFILE_CritSect
);
1721 PROFILE_FlushFile();
1722 LeaveCriticalSection( &PROFILE_CritSect
);
1725 /***********************************************************************
1726 * CloseProfileUserMapping (KERNEL.138)
1728 BOOL WINAPI
CloseProfileUserMapping(void) {
1729 FIXME("(), stub!\n");
1730 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);