4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
15 #include <sys/types.h>
23 #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 static const WCHAR wininiW
[] = { 'w','i','n','.','i','n','i',0 };
82 static CRITICAL_SECTION PROFILE_CritSect
= CRITICAL_SECTION_INIT
;
84 static const char hex
[16] = "0123456789ABCDEF";
86 /***********************************************************************
89 * Copy the content of an entry into a buffer, removing quotes, and possibly
90 * translating environment variables.
92 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
;
274 /* convert the .winerc file to the new format */
275 static void convert_config( FILE *in
, const char *output_name
)
277 char buffer
[PROFILE_MAX_LINE_LEN
];
281 /* create the output file, only if it doesn't exist already */
282 int fd
= open( output_name
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666 );
285 MESSAGE( "Could not create new config file '%s': %s\n", output_name
, strerror(errno
) );
289 out
= fdopen( fd
, "w" );
290 fprintf( out
, "WINE REGISTRY Version 2\n" );
291 fprintf( out
, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
292 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, in
))
294 if (buffer
[strlen(buffer
)-1] == '\n') buffer
[strlen(buffer
)-1] = 0;
296 while (*p
&& PROFILE_isspace(*p
)) p
++;
297 if (*p
== '[') /* section start */
299 if ((p2
= strrchr( p
, ']' )))
303 fprintf( out
, "[%s]\n", p
);
308 if (*p
== ';' || *p
== '#')
310 fprintf( out
, "%s\n", p
);
315 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
317 if ((p2
= strchr( p
, '=' )) != NULL
)
320 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
322 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
327 fprintf( out
, "\n" );
333 if (*p
== '\\') fputc( '\\', out
);
337 fprintf( out
, "\" = \"" );
342 if (*p2
== '\\') fputc( '\\', out
);
347 fprintf( out
, "\"\n" );
353 /***********************************************************************
354 * PROFILE_DeleteSection
356 * Delete a section from a profile tree.
358 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
362 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, name
))
364 PROFILESECTION
*to_del
= *section
;
365 *section
= to_del
->next
;
367 PROFILE_Free( to_del
);
370 section
= &(*section
)->next
;
376 /***********************************************************************
379 * Delete a key from a profile tree.
381 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
382 LPCSTR section_name
, LPCSTR key_name
)
386 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
388 PROFILEKEY
**key
= &(*section
)->key
;
391 if (!strcasecmp( (*key
)->name
, key_name
))
393 PROFILEKEY
*to_del
= *key
;
395 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
396 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
397 HeapFree( GetProcessHeap(), 0, to_del
);
403 section
= &(*section
)->next
;
409 /***********************************************************************
410 * PROFILE_DeleteAllKeys
412 * Delete all keys from a profile tree.
414 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
416 PROFILESECTION
**section
= &CurProfile
->section
;
419 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
421 PROFILEKEY
**key
= &(*section
)->key
;
424 PROFILEKEY
*to_del
= *key
;
426 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
427 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
428 HeapFree( GetProcessHeap(), 0, to_del
);
429 CurProfile
->changed
=TRUE
;
432 section
= &(*section
)->next
;
437 /***********************************************************************
440 * Find a key in a profile tree, optionally creating it.
442 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
,
443 const char *section_name
,
444 const char *key_name
, int create
)
449 while (PROFILE_isspace(*section_name
)) section_name
++;
450 p
= section_name
+ strlen(section_name
) - 1;
451 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
452 seclen
= p
- section_name
+ 1;
454 while (PROFILE_isspace(*key_name
)) key_name
++;
455 p
= key_name
+ strlen(key_name
) - 1;
456 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
457 keylen
= p
- key_name
+ 1;
461 if ( ((*section
)->name
)
462 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
463 && (((*section
)->name
)[seclen
] == '\0') )
465 PROFILEKEY
**key
= &(*section
)->key
;
468 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
469 && (((*key
)->name
)[keylen
] == '\0') )
473 if (!create
) return NULL
;
474 *key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
475 if(*key
== NULL
) return NULL
;
476 (*key
)->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
477 (*key
)->value
= NULL
;
481 section
= &(*section
)->next
;
483 if (!create
) return NULL
;
484 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) );
485 if(*section
== NULL
) return NULL
;
486 (*section
)->name
= HEAP_strdupA( GetProcessHeap(), 0, section_name
);
487 (*section
)->next
= NULL
;
488 (*section
)->key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
489 if((*section
)->key
== NULL
)
491 HeapFree(GetProcessHeap(), 0, *section
);
494 (*section
)->key
->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
495 (*section
)->key
->value
= NULL
;
496 (*section
)->key
->next
= NULL
;
497 return (*section
)->key
;
501 /***********************************************************************
504 * Flush the current profile to disk if changed.
506 static BOOL
PROFILE_FlushFile(void)
508 char *p
, buffer
[MAX_PATHNAME_LEN
];
509 const char *unix_name
;
515 WARN("No current profile!\n");
519 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
520 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
522 /* Try to create it in $HOME/.wine */
523 /* FIXME: this will need a more general solution */
524 strcpy( buffer
, get_config_dir() );
525 p
= buffer
+ strlen(buffer
);
527 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
529 file
= fopen( buffer
, "w" );
535 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
539 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
540 PROFILE_Save( file
, CurProfile
->section
);
542 CurProfile
->changed
= FALSE
;
543 if(!stat(unix_name
,&buf
))
544 CurProfile
->mtime
=buf
.st_mtime
;
549 /***********************************************************************
550 * PROFILE_ReleaseFile
552 * Flush the current profile to disk and remove it from the cache.
554 static void PROFILE_ReleaseFile(void)
557 PROFILE_Free( CurProfile
->section
);
558 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
559 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
560 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
561 CurProfile
->changed
= FALSE
;
562 CurProfile
->section
= NULL
;
563 CurProfile
->dos_name
= NULL
;
564 CurProfile
->unix_name
= NULL
;
565 CurProfile
->filename
= NULL
;
566 CurProfile
->mtime
= 0;
570 /***********************************************************************
573 * Open a profile file, checking the cached file first.
575 static BOOL
PROFILE_Open( LPCSTR filename
)
577 DOS_FULL_NAME full_name
;
578 char buffer
[MAX_PATHNAME_LEN
];
579 char *newdos_name
, *p
;
583 PROFILE
*tempProfile
;
585 /* First time around */
588 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
590 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
591 if(MRUProfile
[i
] == NULL
) break;
592 MRUProfile
[i
]->changed
=FALSE
;
593 MRUProfile
[i
]->section
=NULL
;
594 MRUProfile
[i
]->dos_name
=NULL
;
595 MRUProfile
[i
]->unix_name
=NULL
;
596 MRUProfile
[i
]->filename
=NULL
;
597 MRUProfile
[i
]->mtime
=0;
600 /* Check for a match */
602 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
603 strchr( filename
, ':' ))
605 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
609 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
610 strcat( buffer
, "\\" );
611 strcat( buffer
, filename
);
612 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
615 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
617 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
618 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
623 tempProfile
=MRUProfile
[i
];
625 MRUProfile
[j
]=MRUProfile
[j
-1];
626 CurProfile
=tempProfile
;
628 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
629 TRACE("(%s): already opened (mru=%d)\n",
632 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
638 /* Flush the old current profile */
641 /* Make the oldest profile the current one only in order to get rid of it */
642 if(i
==N_CACHED_PROFILES
)
644 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
645 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
646 MRUProfile
[i
]=MRUProfile
[i
-1];
647 CurProfile
=tempProfile
;
649 if(CurProfile
->filename
) PROFILE_ReleaseFile();
651 /* OK, now that CurProfile is definitely free we assign it our new file */
652 newdos_name
= HEAP_strdupA( GetProcessHeap(), 0, full_name
.short_name
);
653 CurProfile
->dos_name
= newdos_name
;
654 CurProfile
->filename
= HEAP_strdupA( GetProcessHeap(), 0, filename
);
656 /* Try to open the profile file, first in $HOME/.wine */
658 /* FIXME: this will need a more general solution */
659 strcpy( buffer
, get_config_dir() );
660 p
= buffer
+ strlen(buffer
);
662 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
664 if ((file
= fopen( buffer
, "r" )))
666 TRACE("(%s): found it in %s\n",
668 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
673 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0,
674 full_name
.long_name
);
675 if ((file
= fopen( full_name
.long_name
, "r" )))
676 TRACE("(%s): found it in %s\n",
677 filename
, full_name
.long_name
);
682 CurProfile
->section
= PROFILE_Load( file
);
684 if(!stat(CurProfile
->unix_name
,&buf
))
685 CurProfile
->mtime
=buf
.st_mtime
;
689 /* Does not exist yet, we will create it in PROFILE_FlushFile */
690 WARN("profile file %s not found\n", newdos_name
);
696 /***********************************************************************
699 * Returns all keys of a section.
700 * If return_values is TRUE, also include the corresponding values.
702 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
703 LPSTR buffer
, UINT len
, BOOL handle_env
,
708 if(!buffer
) return 0;
712 if (section
->name
&& !strcasecmp( section
->name
, section_name
))
715 for (key
= section
->key
; key
; key
= key
->next
)
718 if (!*key
->name
) continue; /* Skip empty lines */
719 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
720 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
721 len
-= strlen(buffer
) + 1;
722 buffer
+= strlen(buffer
) + 1;
723 if (return_values
&& key
->value
) {
725 PROFILE_CopyEntry ( buffer
,
726 key
->value
, len
- 1, handle_env
);
727 len
-= strlen(buffer
) + 1;
728 buffer
+= strlen(buffer
) + 1;
733 /*If either lpszSection or lpszKey is NULL and the supplied
734 destination buffer is too small to hold all the strings,
735 the last string is truncated and followed by two null characters.
736 In this case, the return value is equal to cchReturnBuffer
744 section
= section
->next
;
746 buffer
[0] = buffer
[1] = '\0';
751 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
755 PROFILESECTION
*section
;
757 if(!buffer
) return 0;
759 for (section
= CurProfile
->section
; section
; section
= section
->next
)
761 l
= strlen(section
->name
);
766 strcpy(buf
, section
->name
);
776 /***********************************************************************
779 * Get a profile string.
781 * Tests with GetPrivateProfileString16, W95a,
782 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
783 * section key_name def_val res buffer
784 * "set1" "1" "x" 43 [data]
785 * "set1" "1 " "x" 43 [data] (!)
786 * "set1" " 1 "' "x" 43 [data] (!)
787 * "set1" "" "x" 1 "x"
788 * "set1" "" "x " 1 "x" (!)
789 * "set1" "" " x " 3 " x" (!)
790 * "set1" NULL "x" 6 "1\02\03\0\0"
791 * "set1" "" "x" 1 "x"
792 * NULL "1" "x" 0 "" (!)
798 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
799 LPCSTR def_val
, LPSTR buffer
, UINT len
)
801 PROFILEKEY
*key
= NULL
;
803 if(!buffer
) return 0;
805 if (!def_val
) def_val
= "";
806 if (key_name
&& key_name
[0])
808 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
809 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
811 TRACE("('%s','%s','%s'): returning '%s'\n",
812 section
, key_name
, def_val
, buffer
);
813 return strlen( buffer
);
815 if (key_name
&& !(key_name
[0]))
816 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
818 if (section
&& section
[0])
819 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
826 /***********************************************************************
829 * Set a profile string.
831 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
834 if (!key_name
) /* Delete a whole section */
836 TRACE("('%s')\n", section_name
);
837 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
839 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
840 this is not an error on application's level.*/
842 else if (!value
) /* Delete a key */
844 TRACE("('%s','%s')\n",
845 section_name
, key_name
);
846 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
847 section_name
, key_name
);
848 return TRUE
; /* same error handling as above */
850 else /* Set the key value */
852 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
854 TRACE("('%s','%s','%s'): \n",
855 section_name
, key_name
, value
);
856 if (!key
) return FALSE
;
859 /* strip the leading spaces. We can safely strip \n\r and
860 * friends too, they should not happen here anyway. */
861 while (PROFILE_isspace(*value
)) value
++;
863 if (!strcmp( key
->value
, value
))
865 TRACE(" no change needed\n" );
866 return TRUE
; /* No change needed */
868 TRACE(" replacing '%s'\n", key
->value
);
869 HeapFree( GetProcessHeap(), 0, key
->value
);
871 else TRACE(" creating key\n" );
872 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
873 CurProfile
->changed
= TRUE
;
879 /***********************************************************************
880 * PROFILE_GetWineIniString
882 * Get a config string from the wine.ini file.
884 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
885 const char *def
, char *buffer
, int len
)
887 char tmp
[PROFILE_MAX_LINE_LEN
];
891 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
894 DWORD count
= sizeof(tmp
);
895 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
898 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
899 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
900 return strlen(buffer
);
904 /***********************************************************************
905 * PROFILE_EnumWineIniString
907 * Get a config string from the wine.ini file.
909 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
910 char *name
, int name_len
, char *buffer
, int len
)
912 char tmp
[PROFILE_MAX_LINE_LEN
];
915 DWORD count
= sizeof(tmp
);
917 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
918 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
922 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
923 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
929 /***********************************************************************
930 * PROFILE_GetWineIniInt
932 * Get a config integer from the wine.ini file.
934 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
940 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
941 if (!buffer
[0]) return def
;
942 result
= strtol( buffer
, &p
, 0 );
943 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
947 /******************************************************************************
949 * int PROFILE_GetWineIniBool(
950 * char const *section,
951 * char const *key_name,
954 * Reads a boolean value from the wine.ini file. This function attempts to
955 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
956 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
957 * true. Anything else results in the return of the default value.
959 * This function uses 1 to indicate true, and 0 for false. You can check
960 * for existence by setting def to something other than 0 or 1 and
961 * examining the return value.
963 int PROFILE_GetWineIniBool(
965 char const *key_name
,
971 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
973 switch(key_value
[0]) {
994 TRACE("(\"%s\", \"%s\", %s), "
995 "[%c], ret %s.\n", section
, key_name
,
996 def
? "TRUE" : "FALSE", key_value
[0],
997 retval
? "TRUE" : "FALSE");
1003 /***********************************************************************
1004 * PROFILE_LoadWineIni
1006 * Load the old .winerc file.
1008 int PROFILE_LoadWineIni(void)
1010 OBJECT_ATTRIBUTES attr
;
1011 UNICODE_STRING nameW
;
1012 char buffer
[MAX_PATHNAME_LEN
];
1018 attr
.Length
= sizeof(attr
);
1019 attr
.RootDirectory
= 0;
1020 attr
.ObjectName
= &nameW
;
1021 attr
.Attributes
= 0;
1022 attr
.SecurityDescriptor
= NULL
;
1023 attr
.SecurityQualityOfService
= NULL
;
1025 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1026 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1027 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1029 ERR("Cannot create config registry key\n" );
1032 RtlFreeUnicodeString( &nameW
);
1035 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1036 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1037 NULL
, REG_OPTION_VOLATILE
, &disp
))
1039 ERR("Cannot create config registry key\n" );
1042 RtlFreeUnicodeString( &nameW
);
1044 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1046 if ((p
= getenv( "HOME" )) != NULL
)
1048 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1049 strcat( buffer
, PROFILE_WineIniName
);
1050 if ((f
= fopen( buffer
, "r" )) != NULL
)
1052 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1056 else WARN("could not get $HOME value for config file.\n" );
1058 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1060 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1065 if (disp
== REG_OPENED_EXISTING_KEY
)
1067 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1068 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed
);
1073 /* convert to the new format */
1074 sprintf( buffer
, "%s/config", get_config_dir() );
1075 convert_config( f
, buffer
);
1078 MESSAGE( "The '%s' configuration file has been converted\n"
1079 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1080 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1081 "and then remove the old one and restart Wine.\n" );
1086 /***********************************************************************
1087 * PROFILE_UsageWineIni
1089 * Explain the wine.ini file to those who don't read documentation.
1090 * Keep below one screenful in length so that error messages above are
1093 void PROFILE_UsageWineIni(void)
1095 MESSAGE("Perhaps you have not properly edited or created "
1096 "your Wine configuration file.\n");
1097 MESSAGE("This is '%s/config'\n", get_config_dir());
1098 /* RTFM, so to say */
1101 /***********************************************************************
1102 * PROFILE_GetStringItem
1104 * Convenience function that turns a string 'xxx, yyy, zzz' into
1105 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1107 char* PROFILE_GetStringItem( char* start
)
1111 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1115 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1117 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1119 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1122 if( lpch
) *lpch
= '\0';
1126 /********************* API functions **********************************/
1128 /***********************************************************************
1129 * GetProfileInt16 (KERNEL.57)
1131 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1133 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1137 /***********************************************************************
1138 * GetProfileIntA (KERNEL32.264)
1140 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1142 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1145 /***********************************************************************
1146 * GetProfileIntW (KERNEL32.264)
1148 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1150 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1154 * undoc_feature means:
1155 * return section names string list if both section and entry are NULL.
1157 static int PROFILE_GetPrivateProfileString( LPCSTR section
, LPCSTR entry
,
1158 LPCSTR def_val
, LPSTR buffer
,
1159 UINT16 len
, LPCSTR filename
,
1160 BOOL undoc_feature
)
1163 LPSTR pDefVal
= NULL
;
1166 filename
= "win.ini";
1168 /* strip any trailing ' ' of def_val. */
1171 LPSTR p
= (LPSTR
)&def_val
[strlen(def_val
)]; /* even "" works ! */
1179 if (*p
== ' ') /* ouch, contained trailing ' ' */
1181 int len
= (int)p
- (int)def_val
;
1182 pDefVal
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1183 strncpy(pDefVal
, def_val
, len
);
1184 pDefVal
[len
] = '\0';
1188 pDefVal
= (LPSTR
)def_val
;
1190 EnterCriticalSection( &PROFILE_CritSect
);
1192 if (PROFILE_Open( filename
)) {
1193 if ((undoc_feature
) && (section
== NULL
) && (entry
== NULL
))
1194 /* undocumented; both section and entry are NULL */
1195 ret
= PROFILE_GetSectionNames(buffer
, len
);
1197 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1199 lstrcpynA( buffer
, pDefVal
, len
);
1200 ret
= strlen( buffer
);
1203 LeaveCriticalSection( &PROFILE_CritSect
);
1205 if (pDefVal
!= def_val
) /* allocated */
1206 HeapFree(GetProcessHeap(), 0, pDefVal
);
1211 /***********************************************************************
1212 * GetPrivateProfileString16 (KERNEL.128)
1214 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1215 LPCSTR def_val
, LPSTR buffer
,
1216 UINT16 len
, LPCSTR filename
)
1218 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1219 buffer
, len
, filename
, FALSE
);
1222 /***********************************************************************
1223 * GetPrivateProfileStringA (KERNEL32.255)
1225 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1226 LPCSTR def_val
, LPSTR buffer
,
1227 UINT len
, LPCSTR filename
)
1229 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1230 buffer
, len
, filename
, TRUE
);
1233 /***********************************************************************
1234 * GetPrivateProfileStringW (KERNEL32.256)
1236 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1237 LPCWSTR def_val
, LPWSTR buffer
,
1238 UINT len
, LPCWSTR filename
)
1240 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1241 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1242 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1243 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1244 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1245 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1246 bufferA
, len
, filenameA
);
1247 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1249 HeapFree( GetProcessHeap(), 0, sectionA
);
1250 HeapFree( GetProcessHeap(), 0, entryA
);
1251 HeapFree( GetProcessHeap(), 0, filenameA
);
1252 HeapFree( GetProcessHeap(), 0, def_valA
);
1253 HeapFree( GetProcessHeap(), 0, bufferA
);
1257 /***********************************************************************
1258 * GetProfileString16 (KERNEL.58)
1260 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1261 LPSTR buffer
, UINT16 len
)
1263 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1264 buffer
, len
, "win.ini", FALSE
);
1267 /***********************************************************************
1268 * GetProfileStringA (KERNEL32.268)
1270 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1271 LPSTR buffer
, UINT len
)
1273 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1274 buffer
, len
, "win.ini", TRUE
);
1277 /***********************************************************************
1278 * GetProfileStringW (KERNEL32.269)
1280 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1281 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1283 return GetPrivateProfileStringW( section
, entry
, def_val
,
1284 buffer
, len
, wininiW
);
1287 /***********************************************************************
1288 * WriteProfileString16 (KERNEL.59)
1290 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1293 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1296 /***********************************************************************
1297 * WriteProfileStringA (KERNEL32.587)
1299 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1302 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1305 /***********************************************************************
1306 * WriteProfileStringW (KERNEL32.588)
1308 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1311 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1315 /***********************************************************************
1316 * GetPrivateProfileInt16 (KERNEL.127)
1318 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1319 INT16 def_val
, LPCSTR filename
)
1321 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1323 if (result
> 65535) return 65535;
1324 if (result
>= 0) return (UINT16
)result
;
1325 if (result
< -32768) return -32768;
1326 return (UINT16
)(INT16
)result
;
1329 /***********************************************************************
1330 * GetPrivateProfileIntA (KERNEL32.251)
1332 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1333 INT def_val
, LPCSTR filename
)
1339 PROFILE_GetPrivateProfileString( section
, entry
, "",
1340 buffer
, sizeof(buffer
), filename
, FALSE
);
1341 if (!buffer
[0]) return (UINT
)def_val
;
1342 result
= strtol( buffer
, &p
, 0 );
1343 if (p
== buffer
) return 0; /* No digits at all */
1344 return (UINT
)result
;
1347 /***********************************************************************
1348 * GetPrivateProfileIntW (KERNEL32.252)
1350 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1351 INT def_val
, LPCWSTR filename
)
1353 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1354 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1355 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1356 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1357 HeapFree( GetProcessHeap(), 0, sectionA
);
1358 HeapFree( GetProcessHeap(), 0, filenameA
);
1359 HeapFree( GetProcessHeap(), 0, entryA
);
1363 /***********************************************************************
1364 * GetPrivateProfileSection16 (KERNEL.418)
1366 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1367 UINT16 len
, LPCSTR filename
)
1369 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1372 /***********************************************************************
1373 * GetPrivateProfileSectionA (KERNEL32.255)
1375 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1376 DWORD len
, LPCSTR filename
)
1380 EnterCriticalSection( &PROFILE_CritSect
);
1382 if (PROFILE_Open( filename
))
1383 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1386 LeaveCriticalSection( &PROFILE_CritSect
);
1391 /***********************************************************************
1392 * GetPrivateProfileSectionW (KERNEL32.256)
1395 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1396 DWORD len
, LPCWSTR filename
)
1399 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1400 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1401 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1402 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1404 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1405 HeapFree( GetProcessHeap(), 0, sectionA
);
1406 HeapFree( GetProcessHeap(), 0, filenameA
);
1407 HeapFree( GetProcessHeap(), 0, bufferA
);
1411 /***********************************************************************
1412 * GetProfileSection16 (KERNEL.419)
1414 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1416 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1419 /***********************************************************************
1420 * GetProfileSectionA (KERNEL32.268)
1422 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1424 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1427 /***********************************************************************
1428 * GetProfileSectionW (KERNEL32)
1430 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1432 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1436 /***********************************************************************
1437 * WritePrivateProfileString16 (KERNEL.129)
1439 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1440 LPCSTR string
, LPCSTR filename
)
1442 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1445 /***********************************************************************
1446 * WritePrivateProfileStringA (KERNEL32.582)
1448 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1449 LPCSTR string
, LPCSTR filename
)
1453 EnterCriticalSection( &PROFILE_CritSect
);
1455 if (PROFILE_Open( filename
))
1457 if (!section
&& !entry
&& !string
)
1458 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1460 ret
= PROFILE_SetString( section
, entry
, string
);
1463 LeaveCriticalSection( &PROFILE_CritSect
);
1467 /***********************************************************************
1468 * WritePrivateProfileStringW (KERNEL32.583)
1470 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1471 LPCWSTR string
, LPCWSTR filename
)
1473 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1474 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1475 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1476 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1477 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1478 stringA
, filenameA
);
1479 HeapFree( GetProcessHeap(), 0, sectionA
);
1480 HeapFree( GetProcessHeap(), 0, entryA
);
1481 HeapFree( GetProcessHeap(), 0, stringA
);
1482 HeapFree( GetProcessHeap(), 0, filenameA
);
1486 /***********************************************************************
1487 * WritePrivateProfileSection16 (KERNEL.416)
1489 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1490 LPCSTR string
, LPCSTR filename
)
1492 return WritePrivateProfileSectionA( section
, string
, filename
);
1495 /***********************************************************************
1496 * WritePrivateProfileSectionA (KERNEL32)
1498 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1499 LPCSTR string
, LPCSTR filename
)
1504 EnterCriticalSection( &PROFILE_CritSect
);
1506 if (PROFILE_Open( filename
)) {
1507 if (!section
&& !string
)
1508 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1509 else if (!string
) /* delete the named section*/
1510 ret
= PROFILE_SetString(section
,NULL
,NULL
);
1512 PROFILE_DeleteAllKeys(section
);
1515 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1516 if((p
=strchr( buf
, '='))){
1518 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1521 HeapFree( GetProcessHeap(), 0, buf
);
1522 string
+= strlen(string
)+1;
1528 LeaveCriticalSection( &PROFILE_CritSect
);
1532 /***********************************************************************
1533 * WritePrivateProfileSectionW (KERNEL32)
1535 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1536 LPCWSTR string
, LPCWSTR filename
)
1539 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1540 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1541 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1542 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1543 HeapFree( GetProcessHeap(), 0, sectionA
);
1544 HeapFree( GetProcessHeap(), 0, stringA
);
1545 HeapFree( GetProcessHeap(), 0, filenameA
);
1549 /***********************************************************************
1550 * WriteProfileSection16 (KERNEL.417)
1552 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1554 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1557 /***********************************************************************
1558 * WriteProfileSectionA (KERNEL32.747)
1560 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1563 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1566 /***********************************************************************
1567 * WriteProfileSectionW (KERNEL32.748)
1569 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1571 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1574 /***********************************************************************
1575 * GetPrivateProfileSectionNames16 (KERNEL.143)
1577 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1582 EnterCriticalSection( &PROFILE_CritSect
);
1584 if (PROFILE_Open( filename
))
1585 ret
= PROFILE_GetSectionNames(buffer
, size
);
1587 LeaveCriticalSection( &PROFILE_CritSect
);
1593 /***********************************************************************
1594 * GetProfileSectionNames16 (KERNEL.142)
1596 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1599 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1603 /***********************************************************************
1604 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1606 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1610 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1614 /***********************************************************************
1615 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1617 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1621 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1622 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1624 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1625 if (size
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, size
))
1627 HeapFree( GetProcessHeap(), 0, bufferA
);
1628 HeapFree( GetProcessHeap(), 0, filenameA
);
1633 /***********************************************************************
1634 * GetPrivateProfileStruct16 (KERNEL.407)
1636 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1637 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1639 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1642 /***********************************************************************
1643 * GetPrivateProfileStructA (KERNEL32.370)
1645 * Should match Win95's behaviour pretty much
1647 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1648 LPVOID buf
, UINT len
, LPCSTR filename
)
1652 EnterCriticalSection( &PROFILE_CritSect
);
1654 if (PROFILE_Open( filename
)) {
1655 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1657 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1658 if (((strlen(k
->value
) - 2) / 2) == len
)
1665 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1666 /* check for invalid chars in ASCII coded hex string */
1667 for (p
=k
->value
; p
< end
; p
++)
1671 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1672 *p
, filename
, section
, key
);
1679 BOOL highnibble
= TRUE
;
1681 LPBYTE binbuf
= (LPBYTE
)buf
;
1683 end
-= 2; /* don't include checksum in output data */
1684 /* translate ASCII hex format into binary data */
1685 for (p
=k
->value
; p
< end
; p
++)
1689 (c
- 'A' + 10) : (c
- '0');
1696 *binbuf
++ = b
; /* feed binary data into output */
1697 chksum
+= b
; /* calculate checksum */
1699 highnibble
^= 1; /* toggle */
1701 /* retrieve stored checksum value */
1703 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1705 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1706 if (b
== (chksum
& 0xff)) /* checksums match ? */
1712 LeaveCriticalSection( &PROFILE_CritSect
);
1717 /***********************************************************************
1718 * GetPrivateProfileStructW (KERNEL32.543)
1720 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1721 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1723 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1724 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1725 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1726 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1728 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1730 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1731 ((LPWSTR
)buffer
)[len
-1] = 0;
1732 HeapFree( GetProcessHeap(), 0, bufferA
);
1733 HeapFree( GetProcessHeap(), 0, sectionA
);
1734 HeapFree( GetProcessHeap(), 0, keyA
);
1735 HeapFree( GetProcessHeap(), 0, filenameA
);
1742 /***********************************************************************
1743 * WritePrivateProfileStruct16 (KERNEL.406)
1745 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1746 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1748 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1751 /***********************************************************************
1752 * WritePrivateProfileStructA (KERNEL32.744)
1754 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1755 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1762 if (!section
&& !key
&& !buf
) /* flush the cache */
1763 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1765 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1766 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1768 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1769 *p
++ = hex
[*binbuf
>> 4];
1770 *p
++ = hex
[*binbuf
& 0xf];
1773 /* checksum is sum & 0xff */
1774 *p
++ = hex
[(sum
& 0xf0) >> 4];
1775 *p
++ = hex
[sum
& 0xf];
1778 EnterCriticalSection( &PROFILE_CritSect
);
1780 if (PROFILE_Open( filename
))
1781 ret
= PROFILE_SetString( section
, key
, outstring
);
1783 LeaveCriticalSection( &PROFILE_CritSect
);
1785 HeapFree( GetProcessHeap(), 0, outstring
);
1790 /***********************************************************************
1791 * WritePrivateProfileStructW (KERNEL32.544)
1793 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1794 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1796 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1797 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1798 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1799 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1801 HeapFree( GetProcessHeap(), 0, sectionA
);
1802 HeapFree( GetProcessHeap(), 0, keyA
);
1803 HeapFree( GetProcessHeap(), 0, filenameA
);
1809 /***********************************************************************
1810 * WriteOutProfiles (KERNEL.315)
1812 void WINAPI
WriteOutProfiles16(void)
1814 EnterCriticalSection( &PROFILE_CritSect
);
1815 PROFILE_FlushFile();
1816 LeaveCriticalSection( &PROFILE_CritSect
);
1819 /***********************************************************************
1820 * CloseProfileUserMapping (KERNEL.138)
1822 BOOL WINAPI
CloseProfileUserMapping(void) {
1823 FIXME("(), stub!\n");
1824 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);