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;
727 if (return_values
&& key
->value
) {
729 PROFILE_CopyEntry ( buffer
,
730 key
->value
, len
- 1, handle_env
);
731 len
-= strlen(buffer
) + 1;
732 buffer
+= strlen(buffer
) + 1;
737 /*If either lpszSection or lpszKey is NULL and the supplied
738 destination buffer is too small to hold all the strings,
739 the last string is truncated and followed by two null characters.
740 In this case, the return value is equal to cchReturnBuffer
748 section
= section
->next
;
750 buffer
[0] = buffer
[1] = '\0';
755 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
759 PROFILESECTION
*section
;
761 if(!buffer
) return 0;
763 for (section
= CurProfile
->section
; section
; section
= section
->next
)
765 l
= strlen(section
->name
);
770 strcpy(buf
, section
->name
);
780 /***********************************************************************
783 * Get a profile string.
785 * Tests with GetPrivateProfileString16, W95a,
786 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
787 * section key_name def_val res buffer
788 * "set1" "1" "x" 43 [data]
789 * "set1" "1 " "x" 43 [data] (!)
790 * "set1" " 1 "' "x" 43 [data] (!)
791 * "set1" "" "x" 1 "x"
792 * "set1" "" "x " 1 "x" (!)
793 * "set1" "" " x " 3 " x" (!)
794 * "set1" NULL "x" 6 "1\02\03\0\0"
795 * "set1" "" "x" 1 "x"
796 * NULL "1" "x" 0 "" (!)
802 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
803 LPCSTR def_val
, LPSTR buffer
, UINT len
)
805 PROFILEKEY
*key
= NULL
;
807 if(!buffer
) return 0;
809 if (!def_val
) def_val
= "";
810 if (key_name
&& key_name
[0])
812 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
813 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
815 TRACE("('%s','%s','%s'): returning '%s'\n",
816 section
, key_name
, def_val
, buffer
);
817 return strlen( buffer
);
819 if (key_name
&& !(key_name
[0]))
820 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
822 if (section
&& section
[0])
823 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
830 /***********************************************************************
833 * Set a profile string.
835 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
838 if (!key_name
) /* Delete a whole section */
840 TRACE("('%s')\n", section_name
);
841 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
843 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
844 this is not an error on application's level.*/
846 else if (!value
) /* Delete a key */
848 TRACE("('%s','%s')\n",
849 section_name
, key_name
);
850 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
851 section_name
, key_name
);
852 return TRUE
; /* same error handling as above */
854 else /* Set the key value */
856 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
858 TRACE("('%s','%s','%s'): \n",
859 section_name
, key_name
, value
);
860 if (!key
) return FALSE
;
863 /* strip the leading spaces. We can safely strip \n\r and
864 * friends too, they should not happen here anyway. */
865 while (PROFILE_isspace(*value
)) value
++;
867 if (!strcmp( key
->value
, value
))
869 TRACE(" no change needed\n" );
870 return TRUE
; /* No change needed */
872 TRACE(" replacing '%s'\n", key
->value
);
873 HeapFree( GetProcessHeap(), 0, key
->value
);
875 else TRACE(" creating key\n" );
876 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
877 CurProfile
->changed
= TRUE
;
883 /***********************************************************************
884 * PROFILE_GetWineIniString
886 * Get a config string from the wine.ini file.
888 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
889 const char *def
, char *buffer
, int len
)
891 char tmp
[PROFILE_MAX_LINE_LEN
];
895 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
898 DWORD count
= sizeof(tmp
);
899 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
902 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
903 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
904 return strlen(buffer
);
908 /***********************************************************************
909 * PROFILE_EnumWineIniString
911 * Get a config string from the wine.ini file.
913 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
914 char *name
, int name_len
, char *buffer
, int len
)
916 char tmp
[PROFILE_MAX_LINE_LEN
];
919 DWORD count
= sizeof(tmp
);
921 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
922 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
926 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
927 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
933 /***********************************************************************
934 * PROFILE_GetWineIniInt
936 * Get a config integer from the wine.ini file.
938 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
944 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
945 if (!buffer
[0]) return def
;
946 result
= strtol( buffer
, &p
, 0 );
947 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
951 /******************************************************************************
953 * int PROFILE_GetWineIniBool(
954 * char const *section,
955 * char const *key_name,
958 * Reads a boolean value from the wine.ini file. This function attempts to
959 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
960 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
961 * true. Anything else results in the return of the default value.
963 * This function uses 1 to indicate true, and 0 for false. You can check
964 * for existence by setting def to something other than 0 or 1 and
965 * examining the return value.
967 int PROFILE_GetWineIniBool(
969 char const *key_name
,
975 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
977 switch(key_value
[0]) {
998 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section
, key_name
,
999 def
? "TRUE" : "FALSE", key_value
[0],
1000 retval
? "TRUE" : "FALSE");
1006 /***********************************************************************
1007 * PROFILE_LoadWineIni
1009 * Load the old .winerc file.
1011 int PROFILE_LoadWineIni(void)
1013 OBJECT_ATTRIBUTES attr
;
1014 UNICODE_STRING nameW
;
1015 char buffer
[MAX_PATHNAME_LEN
];
1021 attr
.Length
= sizeof(attr
);
1022 attr
.RootDirectory
= 0;
1023 attr
.ObjectName
= &nameW
;
1024 attr
.Attributes
= 0;
1025 attr
.SecurityDescriptor
= NULL
;
1026 attr
.SecurityQualityOfService
= NULL
;
1028 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1029 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1030 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1032 ERR("Cannot create config registry key\n" );
1035 RtlFreeUnicodeString( &nameW
);
1038 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1039 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1040 NULL
, REG_OPTION_VOLATILE
, &disp
))
1042 ERR("Cannot create config registry key\n" );
1045 RtlFreeUnicodeString( &nameW
);
1047 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1049 if ((p
= getenv( "HOME" )) != NULL
)
1051 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1052 strcat( buffer
, PROFILE_WineIniName
);
1053 if ((f
= fopen( buffer
, "r" )) != NULL
)
1055 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1059 else WARN("could not get $HOME value for config file.\n" );
1061 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1063 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1068 if (disp
== REG_OPENED_EXISTING_KEY
)
1070 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1071 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed
);
1076 /* convert to the new format */
1077 sprintf( buffer
, "%s/config", get_config_dir() );
1078 convert_config( f
, buffer
);
1081 MESSAGE( "The '%s' configuration file has been converted\n"
1082 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1083 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1084 "and then remove the old one and restart Wine.\n" );
1089 /***********************************************************************
1090 * PROFILE_UsageWineIni
1092 * Explain the wine.ini file to those who don't read documentation.
1093 * Keep below one screenful in length so that error messages above are
1096 void PROFILE_UsageWineIni(void)
1098 MESSAGE("Perhaps you have not properly edited or created "
1099 "your Wine configuration file.\n");
1100 MESSAGE("This is '%s/config'\n", get_config_dir());
1101 /* RTFM, so to say */
1104 /***********************************************************************
1105 * PROFILE_GetStringItem
1107 * Convenience function that turns a string 'xxx, yyy, zzz' into
1108 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1110 char* PROFILE_GetStringItem( char* start
)
1114 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1118 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1120 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1122 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1125 if( lpch
) *lpch
= '\0';
1129 /********************* API functions **********************************/
1131 /***********************************************************************
1132 * GetProfileInt (KERNEL.57)
1134 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1136 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1140 /***********************************************************************
1141 * GetProfileIntA (KERNEL32.@)
1143 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1145 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1148 /***********************************************************************
1149 * GetProfileIntW (KERNEL32.@)
1151 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1153 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1157 * undoc_feature means:
1158 * return section names string list if both section and entry are NULL.
1160 static int PROFILE_GetPrivateProfileString( LPCSTR section
, LPCSTR entry
,
1161 LPCSTR def_val
, LPSTR buffer
,
1162 UINT16 len
, LPCSTR filename
,
1163 BOOL undoc_feature
)
1166 LPSTR pDefVal
= NULL
;
1169 filename
= "win.ini";
1171 /* strip any trailing ' ' of def_val. */
1174 LPSTR p
= (LPSTR
)&def_val
[strlen(def_val
)]; /* even "" works ! */
1182 if (*p
== ' ') /* ouch, contained trailing ' ' */
1184 int len
= (int)p
- (int)def_val
;
1185 pDefVal
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1186 strncpy(pDefVal
, def_val
, len
);
1187 pDefVal
[len
] = '\0';
1191 pDefVal
= (LPSTR
)def_val
;
1193 EnterCriticalSection( &PROFILE_CritSect
);
1195 if (PROFILE_Open( filename
)) {
1196 if ((undoc_feature
) && (section
== NULL
) && (entry
== NULL
))
1197 /* undocumented; both section and entry are NULL */
1198 ret
= PROFILE_GetSectionNames(buffer
, len
);
1200 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1202 lstrcpynA( buffer
, pDefVal
, len
);
1203 ret
= strlen( buffer
);
1206 LeaveCriticalSection( &PROFILE_CritSect
);
1208 if (pDefVal
!= def_val
) /* allocated */
1209 HeapFree(GetProcessHeap(), 0, pDefVal
);
1214 /***********************************************************************
1215 * GetPrivateProfileString (KERNEL.128)
1217 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1218 LPCSTR def_val
, LPSTR buffer
,
1219 UINT16 len
, LPCSTR filename
)
1221 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1222 buffer
, len
, filename
, FALSE
);
1225 /***********************************************************************
1226 * GetPrivateProfileStringA (KERNEL32.@)
1228 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1229 LPCSTR def_val
, LPSTR buffer
,
1230 UINT len
, LPCSTR filename
)
1232 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1233 buffer
, len
, filename
, TRUE
);
1236 /***********************************************************************
1237 * GetPrivateProfileStringW (KERNEL32.@)
1239 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1240 LPCWSTR def_val
, LPWSTR buffer
,
1241 UINT len
, LPCWSTR filename
)
1243 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1244 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1245 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1246 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1247 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1248 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1249 bufferA
, len
, filenameA
);
1250 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1252 HeapFree( GetProcessHeap(), 0, sectionA
);
1253 HeapFree( GetProcessHeap(), 0, entryA
);
1254 HeapFree( GetProcessHeap(), 0, filenameA
);
1255 HeapFree( GetProcessHeap(), 0, def_valA
);
1256 HeapFree( GetProcessHeap(), 0, bufferA
);
1260 /***********************************************************************
1261 * GetProfileString (KERNEL.58)
1263 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1264 LPSTR buffer
, UINT16 len
)
1266 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1267 buffer
, len
, "win.ini", FALSE
);
1270 /***********************************************************************
1271 * GetProfileStringA (KERNEL32.@)
1273 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1274 LPSTR buffer
, UINT len
)
1276 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1277 buffer
, len
, "win.ini", TRUE
);
1280 /***********************************************************************
1281 * GetProfileStringW (KERNEL32.@)
1283 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1284 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1286 return GetPrivateProfileStringW( section
, entry
, def_val
,
1287 buffer
, len
, wininiW
);
1290 /***********************************************************************
1291 * WriteProfileString (KERNEL.59)
1293 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1296 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1299 /***********************************************************************
1300 * WriteProfileStringA (KERNEL32.@)
1302 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1305 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1308 /***********************************************************************
1309 * WriteProfileStringW (KERNEL32.@)
1311 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1314 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1318 /***********************************************************************
1319 * GetPrivateProfileInt (KERNEL.127)
1321 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1322 INT16 def_val
, LPCSTR filename
)
1324 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1326 if (result
> 65535) return 65535;
1327 if (result
>= 0) return (UINT16
)result
;
1328 if (result
< -32768) return -32768;
1329 return (UINT16
)(INT16
)result
;
1332 /***********************************************************************
1333 * GetPrivateProfileIntA (KERNEL32.@)
1335 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1336 INT def_val
, LPCSTR filename
)
1342 PROFILE_GetPrivateProfileString( section
, entry
, "",
1343 buffer
, sizeof(buffer
), filename
, FALSE
);
1344 if (!buffer
[0]) return (UINT
)def_val
;
1345 result
= strtol( buffer
, &p
, 0 );
1346 if (p
== buffer
) return 0; /* No digits at all */
1347 return (UINT
)result
;
1350 /***********************************************************************
1351 * GetPrivateProfileIntW (KERNEL32.@)
1353 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1354 INT def_val
, LPCWSTR filename
)
1356 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1357 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1358 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1359 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1360 HeapFree( GetProcessHeap(), 0, sectionA
);
1361 HeapFree( GetProcessHeap(), 0, filenameA
);
1362 HeapFree( GetProcessHeap(), 0, entryA
);
1366 /***********************************************************************
1367 * GetPrivateProfileSection (KERNEL.418)
1369 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1370 UINT16 len
, LPCSTR filename
)
1372 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1375 /***********************************************************************
1376 * GetPrivateProfileSectionA (KERNEL32.@)
1378 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1379 DWORD len
, LPCSTR filename
)
1383 EnterCriticalSection( &PROFILE_CritSect
);
1385 if (PROFILE_Open( filename
))
1386 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1389 LeaveCriticalSection( &PROFILE_CritSect
);
1394 /***********************************************************************
1395 * GetPrivateProfileSectionW (KERNEL32.@)
1398 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1399 DWORD len
, LPCWSTR filename
)
1402 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1403 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1404 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1405 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1407 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1408 HeapFree( GetProcessHeap(), 0, sectionA
);
1409 HeapFree( GetProcessHeap(), 0, filenameA
);
1410 HeapFree( GetProcessHeap(), 0, bufferA
);
1414 /***********************************************************************
1415 * GetProfileSection (KERNEL.419)
1417 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1419 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1422 /***********************************************************************
1423 * GetProfileSectionA (KERNEL32.@)
1425 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1427 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1430 /***********************************************************************
1431 * GetProfileSectionW (KERNEL32.@)
1433 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1435 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1439 /***********************************************************************
1440 * WritePrivateProfileString (KERNEL.129)
1442 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1443 LPCSTR string
, LPCSTR filename
)
1445 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1448 /***********************************************************************
1449 * WritePrivateProfileStringA (KERNEL32.@)
1451 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1452 LPCSTR string
, LPCSTR filename
)
1456 EnterCriticalSection( &PROFILE_CritSect
);
1458 if (PROFILE_Open( filename
))
1460 if (!section
&& !entry
&& !string
)
1461 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1463 ret
= PROFILE_SetString( section
, entry
, string
);
1466 LeaveCriticalSection( &PROFILE_CritSect
);
1470 /***********************************************************************
1471 * WritePrivateProfileStringW (KERNEL32.@)
1473 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1474 LPCWSTR string
, LPCWSTR filename
)
1476 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1477 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1478 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1479 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1480 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1481 stringA
, filenameA
);
1482 HeapFree( GetProcessHeap(), 0, sectionA
);
1483 HeapFree( GetProcessHeap(), 0, entryA
);
1484 HeapFree( GetProcessHeap(), 0, stringA
);
1485 HeapFree( GetProcessHeap(), 0, filenameA
);
1489 /***********************************************************************
1490 * WritePrivateProfileSection (KERNEL.416)
1492 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1493 LPCSTR string
, LPCSTR filename
)
1495 return WritePrivateProfileSectionA( section
, string
, filename
);
1498 /***********************************************************************
1499 * WritePrivateProfileSectionA (KERNEL32.@)
1501 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1502 LPCSTR string
, LPCSTR filename
)
1507 EnterCriticalSection( &PROFILE_CritSect
);
1509 if (PROFILE_Open( filename
)) {
1510 if (!section
&& !string
)
1511 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1512 else if (!string
) /* delete the named section*/
1513 ret
= PROFILE_SetString(section
,NULL
,NULL
);
1515 PROFILE_DeleteAllKeys(section
);
1518 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1519 if((p
=strchr( buf
, '='))){
1521 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1524 HeapFree( GetProcessHeap(), 0, buf
);
1525 string
+= strlen(string
)+1;
1531 LeaveCriticalSection( &PROFILE_CritSect
);
1535 /***********************************************************************
1536 * WritePrivateProfileSectionW (KERNEL32.@)
1538 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1539 LPCWSTR string
, LPCWSTR filename
)
1542 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1543 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1544 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1545 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1546 HeapFree( GetProcessHeap(), 0, sectionA
);
1547 HeapFree( GetProcessHeap(), 0, stringA
);
1548 HeapFree( GetProcessHeap(), 0, filenameA
);
1552 /***********************************************************************
1553 * WriteProfileSection (KERNEL.417)
1555 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1557 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1560 /***********************************************************************
1561 * WriteProfileSectionA (KERNEL32.@)
1563 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1566 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1569 /***********************************************************************
1570 * WriteProfileSectionW (KERNEL32.@)
1572 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1574 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1577 /***********************************************************************
1578 * GetPrivateProfileSectionNames (KERNEL.143)
1580 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1585 EnterCriticalSection( &PROFILE_CritSect
);
1587 if (PROFILE_Open( filename
))
1588 ret
= PROFILE_GetSectionNames(buffer
, size
);
1590 LeaveCriticalSection( &PROFILE_CritSect
);
1596 /***********************************************************************
1597 * GetProfileSectionNames (KERNEL.142)
1599 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1602 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1606 /***********************************************************************
1607 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1609 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1613 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1617 /***********************************************************************
1618 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1620 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1624 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1625 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1627 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1628 if (size
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, size
))
1630 HeapFree( GetProcessHeap(), 0, bufferA
);
1631 HeapFree( GetProcessHeap(), 0, filenameA
);
1636 /***********************************************************************
1637 * GetPrivateProfileStruct (KERNEL.407)
1639 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1640 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1642 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1645 /***********************************************************************
1646 * GetPrivateProfileStructA (KERNEL32.@)
1648 * Should match Win95's behaviour pretty much
1650 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1651 LPVOID buf
, UINT len
, LPCSTR filename
)
1655 EnterCriticalSection( &PROFILE_CritSect
);
1657 if (PROFILE_Open( filename
)) {
1658 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1660 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1661 if (((strlen(k
->value
) - 2) / 2) == len
)
1668 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1669 /* check for invalid chars in ASCII coded hex string */
1670 for (p
=k
->value
; p
< end
; p
++)
1674 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1675 *p
, filename
, section
, key
);
1682 BOOL highnibble
= TRUE
;
1684 LPBYTE binbuf
= (LPBYTE
)buf
;
1686 end
-= 2; /* don't include checksum in output data */
1687 /* translate ASCII hex format into binary data */
1688 for (p
=k
->value
; p
< end
; p
++)
1692 (c
- 'A' + 10) : (c
- '0');
1699 *binbuf
++ = b
; /* feed binary data into output */
1700 chksum
+= b
; /* calculate checksum */
1702 highnibble
^= 1; /* toggle */
1704 /* retrieve stored checksum value */
1706 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1708 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1709 if (b
== (chksum
& 0xff)) /* checksums match ? */
1715 LeaveCriticalSection( &PROFILE_CritSect
);
1720 /***********************************************************************
1721 * GetPrivateProfileStructW (KERNEL32.@)
1723 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1724 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1726 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1727 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1728 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1729 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1731 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1733 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1734 ((LPWSTR
)buffer
)[len
-1] = 0;
1735 HeapFree( GetProcessHeap(), 0, bufferA
);
1736 HeapFree( GetProcessHeap(), 0, sectionA
);
1737 HeapFree( GetProcessHeap(), 0, keyA
);
1738 HeapFree( GetProcessHeap(), 0, filenameA
);
1745 /***********************************************************************
1746 * WritePrivateProfileStruct (KERNEL.406)
1748 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1749 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1751 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1754 /***********************************************************************
1755 * WritePrivateProfileStructA (KERNEL32.@)
1757 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1758 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1765 if (!section
&& !key
&& !buf
) /* flush the cache */
1766 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1768 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1769 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1771 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1772 *p
++ = hex
[*binbuf
>> 4];
1773 *p
++ = hex
[*binbuf
& 0xf];
1776 /* checksum is sum & 0xff */
1777 *p
++ = hex
[(sum
& 0xf0) >> 4];
1778 *p
++ = hex
[sum
& 0xf];
1781 EnterCriticalSection( &PROFILE_CritSect
);
1783 if (PROFILE_Open( filename
))
1784 ret
= PROFILE_SetString( section
, key
, outstring
);
1786 LeaveCriticalSection( &PROFILE_CritSect
);
1788 HeapFree( GetProcessHeap(), 0, outstring
);
1793 /***********************************************************************
1794 * WritePrivateProfileStructW (KERNEL32.@)
1796 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1797 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1799 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1800 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1801 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1802 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1804 HeapFree( GetProcessHeap(), 0, sectionA
);
1805 HeapFree( GetProcessHeap(), 0, keyA
);
1806 HeapFree( GetProcessHeap(), 0, filenameA
);
1812 /***********************************************************************
1813 * WriteOutProfiles (KERNEL.315)
1815 void WINAPI
WriteOutProfiles16(void)
1817 EnterCriticalSection( &PROFILE_CritSect
);
1818 PROFILE_FlushFile();
1819 LeaveCriticalSection( &PROFILE_CritSect
);
1822 /***********************************************************************
1823 * CloseProfileUserMapping (KERNEL32.@)
1825 BOOL WINAPI
CloseProfileUserMapping(void) {
1826 FIXME("(), stub!\n");
1827 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);