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
)
124 lstrcpynA( buffer
, env_p
, len
);
125 buffer_len
= strlen( buffer
);
126 buffer
+= buffer_len
;
132 if (quote
&& (len
> 1)) buffer
--;
137 /***********************************************************************
140 * Save a profile tree to a file.
142 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
146 for ( ; section
; section
= section
->next
)
148 if (section
->name
) fprintf( file
, "\r\n[%s]\r\n", section
->name
);
149 for (key
= section
->key
; key
; key
= key
->next
)
151 fprintf( file
, "%s", key
->name
);
152 if (key
->value
) fprintf( file
, "=%s", key
->value
);
153 fprintf( file
, "\r\n" );
159 /***********************************************************************
162 * Free a profile tree.
164 static void PROFILE_Free( PROFILESECTION
*section
)
166 PROFILESECTION
*next_section
;
167 PROFILEKEY
*key
, *next_key
;
169 for ( ; section
; section
= next_section
)
171 if (section
->name
) HeapFree( GetProcessHeap(), 0, section
->name
);
172 for (key
= section
->key
; key
; key
= next_key
)
174 next_key
= key
->next
;
175 if (key
->name
) HeapFree( GetProcessHeap(), 0, key
->name
);
176 if (key
->value
) HeapFree( GetProcessHeap(), 0, key
->value
);
177 HeapFree( GetProcessHeap(), 0, key
);
179 next_section
= section
->next
;
180 HeapFree( GetProcessHeap(), 0, section
);
184 static inline int PROFILE_isspace(char c
)
186 if (isspace(c
)) return 1;
187 if (c
=='\r' || c
==0x1a) return 1;
188 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
193 /***********************************************************************
196 * Load a profile tree from a file.
198 static PROFILESECTION
*PROFILE_Load( FILE *file
)
200 char buffer
[PROFILE_MAX_LINE_LEN
];
203 PROFILESECTION
*section
, *first_section
;
204 PROFILESECTION
**next_section
;
205 PROFILEKEY
*key
, *prev_key
, **next_key
;
207 first_section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
208 if(first_section
== NULL
) return NULL
;
209 first_section
->name
= NULL
;
210 first_section
->key
= NULL
;
211 first_section
->next
= NULL
;
212 next_section
= &first_section
->next
;
213 next_key
= &first_section
->key
;
216 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
220 while (*p
&& PROFILE_isspace(*p
)) p
++;
221 if (*p
== '[') /* section start */
223 if (!(p2
= strrchr( p
, ']' )))
225 WARN("Invalid section header at line %d: '%s'\n",
232 section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
233 if(section
== NULL
) break;
234 section
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
236 section
->next
= NULL
;
237 *next_section
= section
;
238 next_section
= §ion
->next
;
239 next_key
= §ion
->key
;
242 TRACE("New section: '%s'\n",section
->name
);
249 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
251 if ((p2
= strchr( p
, '=' )) != NULL
)
254 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
256 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
259 if(*p
|| !prev_key
|| *prev_key
->name
)
261 key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) );
262 if(key
== NULL
) break;
263 key
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
264 key
->value
= p2
? HEAP_strdupA( GetProcessHeap(), 0, p2
) : NULL
;
267 next_key
= &key
->next
;
270 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
273 return first_section
;
276 /* convert the .winerc file to the new format */
277 static void convert_config( FILE *in
, const char *output_name
)
279 char buffer
[PROFILE_MAX_LINE_LEN
];
283 /* create the output file, only if it doesn't exist already */
284 int fd
= open( output_name
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666 );
287 MESSAGE( "Could not create new config file '%s': %s\n", output_name
, strerror(errno
) );
291 out
= fdopen( fd
, "w" );
292 fprintf( out
, "WINE REGISTRY Version 2\n" );
293 fprintf( out
, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
294 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, in
))
296 if (buffer
[strlen(buffer
)-1] == '\n') buffer
[strlen(buffer
)-1] = 0;
298 while (*p
&& PROFILE_isspace(*p
)) p
++;
299 if (*p
== '[') /* section start */
301 if ((p2
= strrchr( p
, ']' )))
305 fprintf( out
, "[%s]\n", p
);
310 if (*p
== ';' || *p
== '#')
312 fprintf( out
, "%s\n", p
);
317 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
319 if ((p2
= strchr( p
, '=' )) != NULL
)
322 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
324 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
329 fprintf( out
, "\n" );
335 if (*p
== '\\') fputc( '\\', out
);
339 fprintf( out
, "\" = \"" );
344 if (*p2
== '\\') fputc( '\\', out
);
349 fprintf( out
, "\"\n" );
355 /***********************************************************************
356 * PROFILE_DeleteSection
358 * Delete a section from a profile tree.
360 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
364 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, name
))
366 PROFILESECTION
*to_del
= *section
;
367 *section
= to_del
->next
;
369 PROFILE_Free( to_del
);
372 section
= &(*section
)->next
;
378 /***********************************************************************
381 * Delete a key from a profile tree.
383 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
384 LPCSTR section_name
, LPCSTR key_name
)
388 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
390 PROFILEKEY
**key
= &(*section
)->key
;
393 if (!strcasecmp( (*key
)->name
, key_name
))
395 PROFILEKEY
*to_del
= *key
;
397 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
398 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
399 HeapFree( GetProcessHeap(), 0, to_del
);
405 section
= &(*section
)->next
;
411 /***********************************************************************
412 * PROFILE_DeleteAllKeys
414 * Delete all keys from a profile tree.
416 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
418 PROFILESECTION
**section
= &CurProfile
->section
;
421 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
423 PROFILEKEY
**key
= &(*section
)->key
;
426 PROFILEKEY
*to_del
= *key
;
428 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
429 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
430 HeapFree( GetProcessHeap(), 0, to_del
);
431 CurProfile
->changed
=TRUE
;
434 section
= &(*section
)->next
;
439 /***********************************************************************
442 * Find a key in a profile tree, optionally creating it.
444 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
,
445 const char *section_name
,
446 const char *key_name
, int create
)
451 while (PROFILE_isspace(*section_name
)) section_name
++;
452 p
= section_name
+ strlen(section_name
) - 1;
453 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
454 seclen
= p
- section_name
+ 1;
456 while (PROFILE_isspace(*key_name
)) key_name
++;
457 p
= key_name
+ strlen(key_name
) - 1;
458 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
459 keylen
= p
- key_name
+ 1;
463 if ( ((*section
)->name
)
464 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
465 && (((*section
)->name
)[seclen
] == '\0') )
467 PROFILEKEY
**key
= &(*section
)->key
;
470 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
471 && (((*key
)->name
)[keylen
] == '\0') )
475 if (!create
) return NULL
;
476 *key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
477 if(*key
== NULL
) return NULL
;
478 (*key
)->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
479 (*key
)->value
= NULL
;
483 section
= &(*section
)->next
;
485 if (!create
) return NULL
;
486 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) );
487 if(*section
== NULL
) return NULL
;
488 (*section
)->name
= HEAP_strdupA( GetProcessHeap(), 0, section_name
);
489 (*section
)->next
= NULL
;
490 (*section
)->key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
491 if((*section
)->key
== NULL
)
493 HeapFree(GetProcessHeap(), 0, *section
);
496 (*section
)->key
->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
497 (*section
)->key
->value
= NULL
;
498 (*section
)->key
->next
= NULL
;
499 return (*section
)->key
;
503 /***********************************************************************
506 * Flush the current profile to disk if changed.
508 static BOOL
PROFILE_FlushFile(void)
510 char *p
, buffer
[MAX_PATHNAME_LEN
];
511 const char *unix_name
;
517 WARN("No current profile!\n");
521 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
522 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
524 /* Try to create it in $HOME/.wine */
525 /* FIXME: this will need a more general solution */
526 strcpy( buffer
, get_config_dir() );
527 p
= buffer
+ strlen(buffer
);
529 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
531 file
= fopen( buffer
, "w" );
537 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
541 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
542 PROFILE_Save( file
, CurProfile
->section
);
544 CurProfile
->changed
= FALSE
;
545 if(!stat(unix_name
,&buf
))
546 CurProfile
->mtime
=buf
.st_mtime
;
551 /***********************************************************************
552 * PROFILE_ReleaseFile
554 * Flush the current profile to disk and remove it from the cache.
556 static void PROFILE_ReleaseFile(void)
559 PROFILE_Free( CurProfile
->section
);
560 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
561 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
562 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
563 CurProfile
->changed
= FALSE
;
564 CurProfile
->section
= NULL
;
565 CurProfile
->dos_name
= NULL
;
566 CurProfile
->unix_name
= NULL
;
567 CurProfile
->filename
= NULL
;
568 CurProfile
->mtime
= 0;
572 /***********************************************************************
575 * Open a profile file, checking the cached file first.
577 static BOOL
PROFILE_Open( LPCSTR filename
)
579 DOS_FULL_NAME full_name
;
580 char buffer
[MAX_PATHNAME_LEN
];
581 char *newdos_name
, *p
;
585 PROFILE
*tempProfile
;
587 /* First time around */
590 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
592 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
593 if(MRUProfile
[i
] == NULL
) break;
594 MRUProfile
[i
]->changed
=FALSE
;
595 MRUProfile
[i
]->section
=NULL
;
596 MRUProfile
[i
]->dos_name
=NULL
;
597 MRUProfile
[i
]->unix_name
=NULL
;
598 MRUProfile
[i
]->filename
=NULL
;
599 MRUProfile
[i
]->mtime
=0;
602 /* Check for a match */
604 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
605 strchr( filename
, ':' ))
607 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
611 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
612 strcat( buffer
, "\\" );
613 strcat( buffer
, filename
);
614 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
617 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
619 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
620 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
625 tempProfile
=MRUProfile
[i
];
627 MRUProfile
[j
]=MRUProfile
[j
-1];
628 CurProfile
=tempProfile
;
630 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
631 TRACE("(%s): already opened (mru=%d)\n",
634 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
640 /* Flush the old current profile */
643 /* Make the oldest profile the current one only in order to get rid of it */
644 if(i
==N_CACHED_PROFILES
)
646 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
647 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
648 MRUProfile
[i
]=MRUProfile
[i
-1];
649 CurProfile
=tempProfile
;
651 if(CurProfile
->filename
) PROFILE_ReleaseFile();
653 /* OK, now that CurProfile is definitely free we assign it our new file */
654 newdos_name
= HEAP_strdupA( GetProcessHeap(), 0, full_name
.short_name
);
655 CurProfile
->dos_name
= newdos_name
;
656 CurProfile
->filename
= HEAP_strdupA( GetProcessHeap(), 0, filename
);
658 /* Try to open the profile file, first in $HOME/.wine */
660 /* FIXME: this will need a more general solution */
661 strcpy( buffer
, get_config_dir() );
662 p
= buffer
+ strlen(buffer
);
664 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
666 if ((file
= fopen( buffer
, "r" )))
668 TRACE("(%s): found it in %s\n",
670 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
675 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0,
676 full_name
.long_name
);
677 if ((file
= fopen( full_name
.long_name
, "r" )))
678 TRACE("(%s): found it in %s\n",
679 filename
, full_name
.long_name
);
684 CurProfile
->section
= PROFILE_Load( file
);
686 if(!stat(CurProfile
->unix_name
,&buf
))
687 CurProfile
->mtime
=buf
.st_mtime
;
691 /* Does not exist yet, we will create it in PROFILE_FlushFile */
692 WARN("profile file %s not found\n", newdos_name
);
698 /***********************************************************************
701 * Returns all keys of a section.
702 * If return_values is TRUE, also include the corresponding values.
704 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
705 LPSTR buffer
, UINT len
, BOOL handle_env
,
710 if(!buffer
) return 0;
714 if (section
->name
&& !strcasecmp( section
->name
, section_name
))
717 for (key
= section
->key
; key
; key
= key
->next
)
720 if (!*key
->name
) continue; /* Skip empty lines */
721 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
722 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
723 len
-= strlen(buffer
) + 1;
724 buffer
+= strlen(buffer
) + 1;
725 if (return_values
&& key
->value
) {
727 PROFILE_CopyEntry ( buffer
,
728 key
->value
, len
- 1, handle_env
);
729 len
-= strlen(buffer
) + 1;
730 buffer
+= strlen(buffer
) + 1;
735 /*If either lpszSection or lpszKey is NULL and the supplied
736 destination buffer is too small to hold all the strings,
737 the last string is truncated and followed by two null characters.
738 In this case, the return value is equal to cchReturnBuffer
746 section
= section
->next
;
748 buffer
[0] = buffer
[1] = '\0';
753 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
757 PROFILESECTION
*section
;
759 if(!buffer
) return 0;
761 for (section
= CurProfile
->section
; section
; section
= section
->next
)
763 l
= strlen(section
->name
);
768 strcpy(buf
, section
->name
);
778 /***********************************************************************
781 * Get a profile string.
783 * Tests with GetPrivateProfileString16, W95a,
784 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
785 * section key_name def_val res buffer
786 * "set1" "1" "x" 43 [data]
787 * "set1" "1 " "x" 43 [data] (!)
788 * "set1" " 1 "' "x" 43 [data] (!)
789 * "set1" "" "x" 1 "x"
790 * "set1" "" "x " 1 "x" (!)
791 * "set1" "" " x " 3 " x" (!)
792 * "set1" NULL "x" 6 "1\02\03\0\0"
793 * "set1" "" "x" 1 "x"
794 * NULL "1" "x" 0 "" (!)
800 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
801 LPCSTR def_val
, LPSTR buffer
, UINT len
)
803 PROFILEKEY
*key
= NULL
;
805 if(!buffer
) return 0;
807 if (!def_val
) def_val
= "";
808 if (key_name
&& key_name
[0])
810 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
811 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
813 TRACE("('%s','%s','%s'): returning '%s'\n",
814 section
, key_name
, def_val
, buffer
);
815 return strlen( buffer
);
817 if (key_name
&& !(key_name
[0]))
818 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
820 if (section
&& section
[0])
821 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
828 /***********************************************************************
831 * Set a profile string.
833 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
836 if (!key_name
) /* Delete a whole section */
838 TRACE("('%s')\n", section_name
);
839 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
841 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
842 this is not an error on application's level.*/
844 else if (!value
) /* Delete a key */
846 TRACE("('%s','%s')\n",
847 section_name
, key_name
);
848 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
849 section_name
, key_name
);
850 return TRUE
; /* same error handling as above */
852 else /* Set the key value */
854 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
856 TRACE("('%s','%s','%s'): \n",
857 section_name
, key_name
, value
);
858 if (!key
) return FALSE
;
861 /* strip the leading spaces. We can safely strip \n\r and
862 * friends too, they should not happen here anyway. */
863 while (PROFILE_isspace(*value
)) value
++;
865 if (!strcmp( key
->value
, value
))
867 TRACE(" no change needed\n" );
868 return TRUE
; /* No change needed */
870 TRACE(" replacing '%s'\n", key
->value
);
871 HeapFree( GetProcessHeap(), 0, key
->value
);
873 else TRACE(" creating key\n" );
874 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
875 CurProfile
->changed
= TRUE
;
881 /***********************************************************************
882 * PROFILE_GetWineIniString
884 * Get a config string from the wine.ini file.
886 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
887 const char *def
, char *buffer
, int len
)
889 char tmp
[PROFILE_MAX_LINE_LEN
];
893 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
896 DWORD count
= sizeof(tmp
);
897 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
900 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
901 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
902 return strlen(buffer
);
906 /***********************************************************************
907 * PROFILE_EnumWineIniString
909 * Get a config string from the wine.ini file.
911 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
912 char *name
, int name_len
, char *buffer
, int len
)
914 char tmp
[PROFILE_MAX_LINE_LEN
];
917 DWORD count
= sizeof(tmp
);
919 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
920 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
924 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
925 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
931 /***********************************************************************
932 * PROFILE_GetWineIniInt
934 * Get a config integer from the wine.ini file.
936 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
942 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
943 if (!buffer
[0]) return def
;
944 result
= strtol( buffer
, &p
, 0 );
945 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
949 /******************************************************************************
951 * int PROFILE_GetWineIniBool(
952 * char const *section,
953 * char const *key_name,
956 * Reads a boolean value from the wine.ini file. This function attempts to
957 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
958 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
959 * true. Anything else results in the return of the default value.
961 * This function uses 1 to indicate true, and 0 for false. You can check
962 * for existence by setting def to something other than 0 or 1 and
963 * examining the return value.
965 int PROFILE_GetWineIniBool(
967 char const *key_name
,
973 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
975 switch(key_value
[0]) {
996 TRACE("(\"%s\", \"%s\", %s), "
997 "[%c], ret %s.\n", section
, key_name
,
998 def
? "TRUE" : "FALSE", key_value
[0],
999 retval
? "TRUE" : "FALSE");
1005 /***********************************************************************
1006 * PROFILE_LoadWineIni
1008 * Load the old .winerc file.
1010 int PROFILE_LoadWineIni(void)
1012 OBJECT_ATTRIBUTES attr
;
1013 UNICODE_STRING nameW
;
1014 char buffer
[MAX_PATHNAME_LEN
];
1020 attr
.Length
= sizeof(attr
);
1021 attr
.RootDirectory
= 0;
1022 attr
.ObjectName
= &nameW
;
1023 attr
.Attributes
= 0;
1024 attr
.SecurityDescriptor
= NULL
;
1025 attr
.SecurityQualityOfService
= NULL
;
1027 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1028 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1029 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1031 ERR("Cannot create config registry key\n" );
1034 RtlFreeUnicodeString( &nameW
);
1037 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1038 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1039 NULL
, REG_OPTION_VOLATILE
, &disp
))
1041 ERR("Cannot create config registry key\n" );
1044 RtlFreeUnicodeString( &nameW
);
1046 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1048 if ((p
= getenv( "HOME" )) != NULL
)
1050 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1051 strcat( buffer
, PROFILE_WineIniName
);
1052 if ((f
= fopen( buffer
, "r" )) != NULL
)
1054 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1058 else WARN("could not get $HOME value for config file.\n" );
1060 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1062 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1067 if (disp
== REG_OPENED_EXISTING_KEY
)
1069 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1070 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed
);
1075 /* convert to the new format */
1076 sprintf( buffer
, "%s/config", get_config_dir() );
1077 convert_config( f
, buffer
);
1080 MESSAGE( "The '%s' configuration file has been converted\n"
1081 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1082 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1083 "and then remove the old one and restart Wine.\n" );
1088 /***********************************************************************
1089 * PROFILE_UsageWineIni
1091 * Explain the wine.ini file to those who don't read documentation.
1092 * Keep below one screenful in length so that error messages above are
1095 void PROFILE_UsageWineIni(void)
1097 MESSAGE("Perhaps you have not properly edited or created "
1098 "your Wine configuration file.\n");
1099 MESSAGE("This is '%s/config'\n", get_config_dir());
1100 /* RTFM, so to say */
1103 /***********************************************************************
1104 * PROFILE_GetStringItem
1106 * Convenience function that turns a string 'xxx, yyy, zzz' into
1107 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1109 char* PROFILE_GetStringItem( char* start
)
1113 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1117 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1119 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1121 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1124 if( lpch
) *lpch
= '\0';
1128 /********************* API functions **********************************/
1130 /***********************************************************************
1131 * GetProfileInt16 (KERNEL.57)
1133 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1135 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1139 /***********************************************************************
1140 * GetProfileIntA (KERNEL32.264)
1142 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1144 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1147 /***********************************************************************
1148 * GetProfileIntW (KERNEL32.264)
1150 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1152 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1156 * undoc_feature means:
1157 * return section names string list if both section and entry are NULL.
1159 static int PROFILE_GetPrivateProfileString( LPCSTR section
, LPCSTR entry
,
1160 LPCSTR def_val
, LPSTR buffer
,
1161 UINT16 len
, LPCSTR filename
,
1162 BOOL undoc_feature
)
1165 LPSTR pDefVal
= NULL
;
1168 filename
= "win.ini";
1170 /* strip any trailing ' ' of def_val. */
1173 LPSTR p
= (LPSTR
)&def_val
[strlen(def_val
)]; /* even "" works ! */
1181 if (*p
== ' ') /* ouch, contained trailing ' ' */
1183 int len
= (int)p
- (int)def_val
;
1184 pDefVal
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1185 strncpy(pDefVal
, def_val
, len
);
1186 pDefVal
[len
] = '\0';
1190 pDefVal
= (LPSTR
)def_val
;
1192 EnterCriticalSection( &PROFILE_CritSect
);
1194 if (PROFILE_Open( filename
)) {
1195 if ((undoc_feature
) && (section
== NULL
) && (entry
== NULL
))
1196 /* undocumented; both section and entry are NULL */
1197 ret
= PROFILE_GetSectionNames(buffer
, len
);
1199 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1201 lstrcpynA( buffer
, pDefVal
, len
);
1202 ret
= strlen( buffer
);
1205 LeaveCriticalSection( &PROFILE_CritSect
);
1207 if (pDefVal
!= def_val
) /* allocated */
1208 HeapFree(GetProcessHeap(), 0, pDefVal
);
1213 /***********************************************************************
1214 * GetPrivateProfileString16 (KERNEL.128)
1216 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1217 LPCSTR def_val
, LPSTR buffer
,
1218 UINT16 len
, LPCSTR filename
)
1220 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1221 buffer
, len
, filename
, FALSE
);
1224 /***********************************************************************
1225 * GetPrivateProfileStringA (KERNEL32.255)
1227 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1228 LPCSTR def_val
, LPSTR buffer
,
1229 UINT len
, LPCSTR filename
)
1231 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1232 buffer
, len
, filename
, TRUE
);
1235 /***********************************************************************
1236 * GetPrivateProfileStringW (KERNEL32.256)
1238 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1239 LPCWSTR def_val
, LPWSTR buffer
,
1240 UINT len
, LPCWSTR filename
)
1242 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1243 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1244 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1245 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1246 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1247 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1248 bufferA
, len
, filenameA
);
1249 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1251 HeapFree( GetProcessHeap(), 0, sectionA
);
1252 HeapFree( GetProcessHeap(), 0, entryA
);
1253 HeapFree( GetProcessHeap(), 0, filenameA
);
1254 HeapFree( GetProcessHeap(), 0, def_valA
);
1255 HeapFree( GetProcessHeap(), 0, bufferA
);
1259 /***********************************************************************
1260 * GetProfileString16 (KERNEL.58)
1262 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1263 LPSTR buffer
, UINT16 len
)
1265 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1266 buffer
, len
, "win.ini", FALSE
);
1269 /***********************************************************************
1270 * GetProfileStringA (KERNEL32.268)
1272 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1273 LPSTR buffer
, UINT len
)
1275 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1276 buffer
, len
, "win.ini", TRUE
);
1279 /***********************************************************************
1280 * GetProfileStringW (KERNEL32.269)
1282 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1283 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1285 return GetPrivateProfileStringW( section
, entry
, def_val
,
1286 buffer
, len
, wininiW
);
1289 /***********************************************************************
1290 * WriteProfileString16 (KERNEL.59)
1292 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1295 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1298 /***********************************************************************
1299 * WriteProfileStringA (KERNEL32.587)
1301 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1304 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1307 /***********************************************************************
1308 * WriteProfileStringW (KERNEL32.588)
1310 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1313 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1317 /***********************************************************************
1318 * GetPrivateProfileInt16 (KERNEL.127)
1320 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1321 INT16 def_val
, LPCSTR filename
)
1323 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1325 if (result
> 65535) return 65535;
1326 if (result
>= 0) return (UINT16
)result
;
1327 if (result
< -32768) return -32768;
1328 return (UINT16
)(INT16
)result
;
1331 /***********************************************************************
1332 * GetPrivateProfileIntA (KERNEL32.251)
1334 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1335 INT def_val
, LPCSTR filename
)
1341 PROFILE_GetPrivateProfileString( section
, entry
, "",
1342 buffer
, sizeof(buffer
), filename
, FALSE
);
1343 if (!buffer
[0]) return (UINT
)def_val
;
1344 result
= strtol( buffer
, &p
, 0 );
1345 if (p
== buffer
) return 0; /* No digits at all */
1346 return (UINT
)result
;
1349 /***********************************************************************
1350 * GetPrivateProfileIntW (KERNEL32.252)
1352 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1353 INT def_val
, LPCWSTR filename
)
1355 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1356 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1357 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1358 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1359 HeapFree( GetProcessHeap(), 0, sectionA
);
1360 HeapFree( GetProcessHeap(), 0, filenameA
);
1361 HeapFree( GetProcessHeap(), 0, entryA
);
1365 /***********************************************************************
1366 * GetPrivateProfileSection16 (KERNEL.418)
1368 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1369 UINT16 len
, LPCSTR filename
)
1371 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1374 /***********************************************************************
1375 * GetPrivateProfileSectionA (KERNEL32.255)
1377 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1378 DWORD len
, LPCSTR filename
)
1382 EnterCriticalSection( &PROFILE_CritSect
);
1384 if (PROFILE_Open( filename
))
1385 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1388 LeaveCriticalSection( &PROFILE_CritSect
);
1393 /***********************************************************************
1394 * GetPrivateProfileSectionW (KERNEL32.256)
1397 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1398 DWORD len
, LPCWSTR filename
)
1401 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1402 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1403 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1404 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1406 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1407 HeapFree( GetProcessHeap(), 0, sectionA
);
1408 HeapFree( GetProcessHeap(), 0, filenameA
);
1409 HeapFree( GetProcessHeap(), 0, bufferA
);
1413 /***********************************************************************
1414 * GetProfileSection16 (KERNEL.419)
1416 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1418 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1421 /***********************************************************************
1422 * GetProfileSectionA (KERNEL32.268)
1424 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1426 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1429 /***********************************************************************
1430 * GetProfileSectionW (KERNEL32)
1432 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1434 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1438 /***********************************************************************
1439 * WritePrivateProfileString16 (KERNEL.129)
1441 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1442 LPCSTR string
, LPCSTR filename
)
1444 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1447 /***********************************************************************
1448 * WritePrivateProfileStringA (KERNEL32.582)
1450 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1451 LPCSTR string
, LPCSTR filename
)
1455 EnterCriticalSection( &PROFILE_CritSect
);
1457 if (PROFILE_Open( filename
))
1459 if (!section
&& !entry
&& !string
)
1460 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1462 ret
= PROFILE_SetString( section
, entry
, string
);
1465 LeaveCriticalSection( &PROFILE_CritSect
);
1469 /***********************************************************************
1470 * WritePrivateProfileStringW (KERNEL32.583)
1472 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1473 LPCWSTR string
, LPCWSTR filename
)
1475 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1476 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1477 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1478 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1479 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1480 stringA
, filenameA
);
1481 HeapFree( GetProcessHeap(), 0, sectionA
);
1482 HeapFree( GetProcessHeap(), 0, entryA
);
1483 HeapFree( GetProcessHeap(), 0, stringA
);
1484 HeapFree( GetProcessHeap(), 0, filenameA
);
1488 /***********************************************************************
1489 * WritePrivateProfileSection16 (KERNEL.416)
1491 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1492 LPCSTR string
, LPCSTR filename
)
1494 return WritePrivateProfileSectionA( section
, string
, filename
);
1497 /***********************************************************************
1498 * WritePrivateProfileSectionA (KERNEL32)
1500 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1501 LPCSTR string
, LPCSTR filename
)
1506 EnterCriticalSection( &PROFILE_CritSect
);
1508 if (PROFILE_Open( filename
)) {
1509 if (!section
&& !string
)
1510 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1511 else if (!string
) /* delete the named section*/
1512 ret
= PROFILE_SetString(section
,NULL
,NULL
);
1514 PROFILE_DeleteAllKeys(section
);
1517 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1518 if((p
=strchr( buf
, '='))){
1520 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1523 HeapFree( GetProcessHeap(), 0, buf
);
1524 string
+= strlen(string
)+1;
1530 LeaveCriticalSection( &PROFILE_CritSect
);
1534 /***********************************************************************
1535 * WritePrivateProfileSectionW (KERNEL32)
1537 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1538 LPCWSTR string
, LPCWSTR filename
)
1541 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1542 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1543 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1544 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1545 HeapFree( GetProcessHeap(), 0, sectionA
);
1546 HeapFree( GetProcessHeap(), 0, stringA
);
1547 HeapFree( GetProcessHeap(), 0, filenameA
);
1551 /***********************************************************************
1552 * WriteProfileSection16 (KERNEL.417)
1554 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1556 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1559 /***********************************************************************
1560 * WriteProfileSectionA (KERNEL32.747)
1562 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1565 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1568 /***********************************************************************
1569 * WriteProfileSectionW (KERNEL32.748)
1571 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1573 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1576 /***********************************************************************
1577 * GetPrivateProfileSectionNames16 (KERNEL.143)
1579 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1584 EnterCriticalSection( &PROFILE_CritSect
);
1586 if (PROFILE_Open( filename
))
1587 ret
= PROFILE_GetSectionNames(buffer
, size
);
1589 LeaveCriticalSection( &PROFILE_CritSect
);
1595 /***********************************************************************
1596 * GetProfileSectionNames16 (KERNEL.142)
1598 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1601 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1605 /***********************************************************************
1606 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1608 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1612 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1616 /***********************************************************************
1617 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1619 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1623 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1624 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1626 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1627 if (size
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, size
))
1629 HeapFree( GetProcessHeap(), 0, bufferA
);
1630 HeapFree( GetProcessHeap(), 0, filenameA
);
1635 /***********************************************************************
1636 * GetPrivateProfileStruct16 (KERNEL.407)
1638 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1639 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1641 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1644 /***********************************************************************
1645 * GetPrivateProfileStructA (KERNEL32.370)
1647 * Should match Win95's behaviour pretty much
1649 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1650 LPVOID buf
, UINT len
, LPCSTR filename
)
1654 EnterCriticalSection( &PROFILE_CritSect
);
1656 if (PROFILE_Open( filename
)) {
1657 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1659 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1660 if (((strlen(k
->value
) - 2) / 2) == len
)
1667 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1668 /* check for invalid chars in ASCII coded hex string */
1669 for (p
=k
->value
; p
< end
; p
++)
1673 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1674 *p
, filename
, section
, key
);
1681 BOOL highnibble
= TRUE
;
1683 LPBYTE binbuf
= (LPBYTE
)buf
;
1685 end
-= 2; /* don't include checksum in output data */
1686 /* translate ASCII hex format into binary data */
1687 for (p
=k
->value
; p
< end
; p
++)
1691 (c
- 'A' + 10) : (c
- '0');
1698 *binbuf
++ = b
; /* feed binary data into output */
1699 chksum
+= b
; /* calculate checksum */
1701 highnibble
^= 1; /* toggle */
1703 /* retrieve stored checksum value */
1705 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1707 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1708 if (b
== (chksum
& 0xff)) /* checksums match ? */
1714 LeaveCriticalSection( &PROFILE_CritSect
);
1719 /***********************************************************************
1720 * GetPrivateProfileStructW (KERNEL32.543)
1722 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1723 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1725 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1726 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1727 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1728 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1730 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1732 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1733 ((LPWSTR
)buffer
)[len
-1] = 0;
1734 HeapFree( GetProcessHeap(), 0, bufferA
);
1735 HeapFree( GetProcessHeap(), 0, sectionA
);
1736 HeapFree( GetProcessHeap(), 0, keyA
);
1737 HeapFree( GetProcessHeap(), 0, filenameA
);
1744 /***********************************************************************
1745 * WritePrivateProfileStruct16 (KERNEL.406)
1747 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1748 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1750 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1753 /***********************************************************************
1754 * WritePrivateProfileStructA (KERNEL32.744)
1756 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1757 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1764 if (!section
&& !key
&& !buf
) /* flush the cache */
1765 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1767 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1768 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1770 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1771 *p
++ = hex
[*binbuf
>> 4];
1772 *p
++ = hex
[*binbuf
& 0xf];
1775 /* checksum is sum & 0xff */
1776 *p
++ = hex
[(sum
& 0xf0) >> 4];
1777 *p
++ = hex
[sum
& 0xf];
1780 EnterCriticalSection( &PROFILE_CritSect
);
1782 if (PROFILE_Open( filename
))
1783 ret
= PROFILE_SetString( section
, key
, outstring
);
1785 LeaveCriticalSection( &PROFILE_CritSect
);
1787 HeapFree( GetProcessHeap(), 0, outstring
);
1792 /***********************************************************************
1793 * WritePrivateProfileStructW (KERNEL32.544)
1795 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1796 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1798 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1799 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1800 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1801 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1803 HeapFree( GetProcessHeap(), 0, sectionA
);
1804 HeapFree( GetProcessHeap(), 0, keyA
);
1805 HeapFree( GetProcessHeap(), 0, filenameA
);
1811 /***********************************************************************
1812 * WriteOutProfiles (KERNEL.315)
1814 void WINAPI
WriteOutProfiles16(void)
1816 EnterCriticalSection( &PROFILE_CritSect
);
1817 PROFILE_FlushFile();
1818 LeaveCriticalSection( &PROFILE_CritSect
);
1821 /***********************************************************************
1822 * CloseProfileUserMapping (KERNEL.138)
1824 BOOL WINAPI
CloseProfileUserMapping(void) {
1825 FIXME("(), stub!\n");
1826 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);