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"
29 #include "wine/server.h"
31 DEFAULT_DEBUG_CHANNEL(profile
);
33 typedef struct tagPROFILEKEY
36 struct tagPROFILEKEY
*next
;
40 typedef struct tagPROFILESECTION
42 struct tagPROFILEKEY
*key
;
43 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 for (key
= section
->key
; key
; key
= next_key
)
173 next_key
= key
->next
;
174 if (key
->value
) HeapFree( GetProcessHeap(), 0, key
->value
);
175 HeapFree( GetProcessHeap(), 0, key
);
177 next_section
= section
->next
;
178 HeapFree( GetProcessHeap(), 0, section
);
182 static inline int PROFILE_isspace(char c
)
184 if (isspace(c
)) return 1;
185 if (c
=='\r' || c
==0x1a) return 1;
186 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
191 /***********************************************************************
194 * Load a profile tree from a file.
196 static PROFILESECTION
*PROFILE_Load( FILE *file
)
198 char buffer
[PROFILE_MAX_LINE_LEN
];
201 PROFILESECTION
*section
, *first_section
;
202 PROFILESECTION
**next_section
;
203 PROFILEKEY
*key
, *prev_key
, **next_key
;
205 first_section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
206 if(first_section
== NULL
) return NULL
;
207 first_section
->name
[0] = 0;
208 first_section
->key
= NULL
;
209 first_section
->next
= NULL
;
210 next_section
= &first_section
->next
;
211 next_key
= &first_section
->key
;
214 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
218 while (*p
&& PROFILE_isspace(*p
)) p
++;
219 if (*p
== '[') /* section start */
221 if (!(p2
= strrchr( p
, ']' )))
223 WARN("Invalid section header at line %d: '%s'\n",
230 if (!(section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) + strlen(p
) )))
232 strcpy( section
->name
, p
);
234 section
->next
= NULL
;
235 *next_section
= section
;
236 next_section
= §ion
->next
;
237 next_key
= §ion
->key
;
240 TRACE("New section: '%s'\n",section
->name
);
247 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
249 if ((p2
= strchr( p
, '=' )) != NULL
)
252 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
254 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
257 if(*p
|| !prev_key
|| *prev_key
->name
)
259 if (!(key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) + strlen(p
) ))) break;
260 strcpy( key
->name
, p
);
263 key
->value
= HeapAlloc( GetProcessHeap(), 0, strlen(p2
)+1 );
264 strcpy( key
->value
, p2
);
266 else key
->value
= NULL
;
270 next_key
= &key
->next
;
273 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
276 return first_section
;
279 /* convert the .winerc file to the new format */
280 static void convert_config( FILE *in
, const char *output_name
)
282 char buffer
[PROFILE_MAX_LINE_LEN
];
286 /* create the output file, only if it doesn't exist already */
287 int fd
= open( output_name
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666 );
290 MESSAGE( "Could not create new config file '%s': %s\n", output_name
, strerror(errno
) );
294 out
= fdopen( fd
, "w" );
295 fprintf( out
, "WINE REGISTRY Version 2\n" );
296 fprintf( out
, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
297 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, in
))
299 if (buffer
[strlen(buffer
)-1] == '\n') buffer
[strlen(buffer
)-1] = 0;
301 while (*p
&& PROFILE_isspace(*p
)) p
++;
302 if (*p
== '[') /* section start */
304 if ((p2
= strrchr( p
, ']' )))
308 fprintf( out
, "[%s]\n", p
);
313 if (*p
== ';' || *p
== '#')
315 fprintf( out
, "%s\n", p
);
320 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
322 if ((p2
= strchr( p
, '=' )) != NULL
)
325 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
327 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
332 fprintf( out
, "\n" );
338 if (*p
== '\\') fputc( '\\', out
);
342 fprintf( out
, "\" = \"" );
347 if (*p2
== '\\') fputc( '\\', out
);
352 fprintf( out
, "\"\n" );
358 /***********************************************************************
359 * PROFILE_DeleteSection
361 * Delete a section from a profile tree.
363 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
367 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, name
))
369 PROFILESECTION
*to_del
= *section
;
370 *section
= to_del
->next
;
372 PROFILE_Free( to_del
);
375 section
= &(*section
)->next
;
381 /***********************************************************************
384 * Delete a key from a profile tree.
386 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
387 LPCSTR section_name
, LPCSTR key_name
)
391 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, section_name
))
393 PROFILEKEY
**key
= &(*section
)->key
;
396 if (!strcasecmp( (*key
)->name
, key_name
))
398 PROFILEKEY
*to_del
= *key
;
400 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
401 HeapFree( GetProcessHeap(), 0, to_del
);
407 section
= &(*section
)->next
;
413 /***********************************************************************
414 * PROFILE_DeleteAllKeys
416 * Delete all keys from a profile tree.
418 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
420 PROFILESECTION
**section
= &CurProfile
->section
;
423 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, section_name
))
425 PROFILEKEY
**key
= &(*section
)->key
;
428 PROFILEKEY
*to_del
= *key
;
430 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
431 HeapFree( GetProcessHeap(), 0, to_del
);
432 CurProfile
->changed
=TRUE
;
435 section
= &(*section
)->next
;
440 /***********************************************************************
443 * Find a key in a profile tree, optionally creating it.
445 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
,
446 const char *section_name
,
447 const char *key_name
, int create
)
452 while (PROFILE_isspace(*section_name
)) section_name
++;
453 p
= section_name
+ strlen(section_name
) - 1;
454 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
455 seclen
= p
- section_name
+ 1;
457 while (PROFILE_isspace(*key_name
)) key_name
++;
458 p
= key_name
+ strlen(key_name
) - 1;
459 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
460 keylen
= p
- key_name
+ 1;
464 if ( ((*section
)->name
[0])
465 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
466 && (((*section
)->name
)[seclen
] == '\0') )
468 PROFILEKEY
**key
= &(*section
)->key
;
471 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
472 && (((*key
)->name
)[keylen
] == '\0') )
476 if (!create
) return NULL
;
477 if (!(*key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) + strlen(key_name
) )))
479 strcpy( (*key
)->name
, key_name
);
480 (*key
)->value
= NULL
;
484 section
= &(*section
)->next
;
486 if (!create
) return NULL
;
487 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) + strlen(section_name
) );
488 if(*section
== NULL
) return NULL
;
489 strcpy( (*section
)->name
, section_name
);
490 (*section
)->next
= NULL
;
491 if (!((*section
)->key
= HeapAlloc( GetProcessHeap(), 0,
492 sizeof(PROFILEKEY
) + strlen(key_name
) )))
494 HeapFree(GetProcessHeap(), 0, *section
);
497 strcpy( (*section
)->key
->name
, key_name
);
498 (*section
)->key
->value
= NULL
;
499 (*section
)->key
->next
= NULL
;
500 return (*section
)->key
;
504 /***********************************************************************
507 * Flush the current profile to disk if changed.
509 static BOOL
PROFILE_FlushFile(void)
511 char *p
, buffer
[MAX_PATHNAME_LEN
];
512 const char *unix_name
;
518 WARN("No current profile!\n");
522 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
523 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
525 /* Try to create it in $HOME/.wine */
526 /* FIXME: this will need a more general solution */
527 strcpy( buffer
, get_config_dir() );
528 p
= buffer
+ strlen(buffer
);
530 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
532 file
= fopen( buffer
, "w" );
538 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
542 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
543 PROFILE_Save( file
, CurProfile
->section
);
545 CurProfile
->changed
= FALSE
;
546 if(!stat(unix_name
,&buf
))
547 CurProfile
->mtime
=buf
.st_mtime
;
552 /***********************************************************************
553 * PROFILE_ReleaseFile
555 * Flush the current profile to disk and remove it from the cache.
557 static void PROFILE_ReleaseFile(void)
560 PROFILE_Free( CurProfile
->section
);
561 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
562 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
563 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
564 CurProfile
->changed
= FALSE
;
565 CurProfile
->section
= NULL
;
566 CurProfile
->dos_name
= NULL
;
567 CurProfile
->unix_name
= NULL
;
568 CurProfile
->filename
= NULL
;
569 CurProfile
->mtime
= 0;
573 /***********************************************************************
576 * Open a profile file, checking the cached file first.
578 static BOOL
PROFILE_Open( LPCSTR filename
)
580 DOS_FULL_NAME full_name
;
581 char buffer
[MAX_PATHNAME_LEN
];
582 char *newdos_name
, *p
;
586 PROFILE
*tempProfile
;
588 /* First time around */
591 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
593 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
594 if(MRUProfile
[i
] == NULL
) break;
595 MRUProfile
[i
]->changed
=FALSE
;
596 MRUProfile
[i
]->section
=NULL
;
597 MRUProfile
[i
]->dos_name
=NULL
;
598 MRUProfile
[i
]->unix_name
=NULL
;
599 MRUProfile
[i
]->filename
=NULL
;
600 MRUProfile
[i
]->mtime
=0;
603 /* Check for a match */
605 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
606 strchr( filename
, ':' ))
608 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
612 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
613 strcat( buffer
, "\\" );
614 strcat( buffer
, filename
);
615 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
618 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
620 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
621 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
626 tempProfile
=MRUProfile
[i
];
628 MRUProfile
[j
]=MRUProfile
[j
-1];
629 CurProfile
=tempProfile
;
631 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
632 TRACE("(%s): already opened (mru=%d)\n",
635 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
641 /* Flush the old current profile */
644 /* Make the oldest profile the current one only in order to get rid of it */
645 if(i
==N_CACHED_PROFILES
)
647 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
648 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
649 MRUProfile
[i
]=MRUProfile
[i
-1];
650 CurProfile
=tempProfile
;
652 if(CurProfile
->filename
) PROFILE_ReleaseFile();
654 /* OK, now that CurProfile is definitely free we assign it our new file */
655 newdos_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.short_name
)+1 );
656 strcpy( newdos_name
, full_name
.short_name
);
657 CurProfile
->dos_name
= newdos_name
;
658 CurProfile
->filename
= HeapAlloc( GetProcessHeap(), 0, strlen(filename
)+1 );
659 strcpy( CurProfile
->filename
, filename
);
661 /* Try to open the profile file, first in $HOME/.wine */
663 /* FIXME: this will need a more general solution */
664 strcpy( buffer
, get_config_dir() );
665 p
= buffer
+ strlen(buffer
);
667 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
669 if ((file
= fopen( buffer
, "r" )))
671 TRACE("(%s): found it in %s\n",
673 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(buffer
)+1 );
674 strcpy( CurProfile
->unix_name
, buffer
);
679 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.long_name
)+1 );
680 strcpy( CurProfile
->unix_name
, full_name
.long_name
);
681 if ((file
= fopen( full_name
.long_name
, "r" )))
682 TRACE("(%s): found it in %s\n",
683 filename
, full_name
.long_name
);
688 CurProfile
->section
= PROFILE_Load( file
);
690 if(!stat(CurProfile
->unix_name
,&buf
))
691 CurProfile
->mtime
=buf
.st_mtime
;
695 /* Does not exist yet, we will create it in PROFILE_FlushFile */
696 WARN("profile file %s not found\n", newdos_name
);
702 /***********************************************************************
705 * Returns all keys of a section.
706 * If return_values is TRUE, also include the corresponding values.
708 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
709 LPSTR buffer
, UINT len
, BOOL handle_env
,
714 if(!buffer
) return 0;
718 if (section
->name
[0] && !strcasecmp( section
->name
, section_name
))
721 for (key
= section
->key
; key
; key
= key
->next
)
724 if (!*key
->name
) continue; /* Skip empty lines */
725 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
726 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
727 len
-= strlen(buffer
) + 1;
728 buffer
+= strlen(buffer
) + 1;
731 if (return_values
&& key
->value
) {
733 PROFILE_CopyEntry ( buffer
,
734 key
->value
, len
- 1, handle_env
);
735 len
-= strlen(buffer
) + 1;
736 buffer
+= strlen(buffer
) + 1;
741 /*If either lpszSection or lpszKey is NULL and the supplied
742 destination buffer is too small to hold all the strings,
743 the last string is truncated and followed by two null characters.
744 In this case, the return value is equal to cchReturnBuffer
752 section
= section
->next
;
754 buffer
[0] = buffer
[1] = '\0';
759 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
763 PROFILESECTION
*section
;
765 if(!buffer
) return 0;
767 for (section
= CurProfile
->section
; section
; section
= section
->next
)
768 if (section
->name
[0]) {
769 l
= strlen(section
->name
);
774 strcpy(buf
, section
->name
);
784 /***********************************************************************
787 * Get a profile string.
789 * Tests with GetPrivateProfileString16, W95a,
790 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
791 * section key_name def_val res buffer
792 * "set1" "1" "x" 43 [data]
793 * "set1" "1 " "x" 43 [data] (!)
794 * "set1" " 1 "' "x" 43 [data] (!)
795 * "set1" "" "x" 1 "x"
796 * "set1" "" "x " 1 "x" (!)
797 * "set1" "" " x " 3 " x" (!)
798 * "set1" NULL "x" 6 "1\02\03\0\0"
799 * "set1" "" "x" 1 "x"
800 * NULL "1" "x" 0 "" (!)
806 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
807 LPCSTR def_val
, LPSTR buffer
, UINT len
)
809 PROFILEKEY
*key
= NULL
;
811 if(!buffer
) return 0;
813 if (!def_val
) def_val
= "";
814 if (key_name
&& key_name
[0])
816 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
817 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
819 TRACE("('%s','%s','%s'): returning '%s'\n",
820 section
, key_name
, def_val
, buffer
);
821 return strlen( buffer
);
823 if (key_name
&& !(key_name
[0]))
824 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
826 if (section
&& section
[0])
827 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
834 /***********************************************************************
837 * Set a profile string.
839 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
842 if (!key_name
) /* Delete a whole section */
844 TRACE("('%s')\n", section_name
);
845 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
847 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
848 this is not an error on application's level.*/
850 else if (!value
) /* Delete a key */
852 TRACE("('%s','%s')\n",
853 section_name
, key_name
);
854 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
855 section_name
, key_name
);
856 return TRUE
; /* same error handling as above */
858 else /* Set the key value */
860 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
862 TRACE("('%s','%s','%s'): \n",
863 section_name
, key_name
, value
);
864 if (!key
) return FALSE
;
867 /* strip the leading spaces. We can safely strip \n\r and
868 * friends too, they should not happen here anyway. */
869 while (PROFILE_isspace(*value
)) value
++;
871 if (!strcmp( key
->value
, value
))
873 TRACE(" no change needed\n" );
874 return TRUE
; /* No change needed */
876 TRACE(" replacing '%s'\n", key
->value
);
877 HeapFree( GetProcessHeap(), 0, key
->value
);
879 else TRACE(" creating key\n" );
880 key
->value
= HeapAlloc( GetProcessHeap(), 0, strlen(value
)+1 );
881 strcpy( key
->value
, value
);
882 CurProfile
->changed
= TRUE
;
888 /***********************************************************************
889 * PROFILE_GetWineIniString
891 * Get a config string from the wine.ini file.
893 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
894 const char *def
, char *buffer
, int len
)
896 char tmp
[PROFILE_MAX_LINE_LEN
];
900 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
903 DWORD count
= sizeof(tmp
);
904 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
907 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
908 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
909 return strlen(buffer
);
913 /***********************************************************************
914 * PROFILE_EnumWineIniString
916 * Get a config string from the wine.ini file.
918 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
919 char *name
, int name_len
, char *buffer
, int len
)
921 char tmp
[PROFILE_MAX_LINE_LEN
];
924 DWORD count
= sizeof(tmp
);
926 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
927 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
931 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
932 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
938 /***********************************************************************
939 * PROFILE_GetWineIniInt
941 * Get a config integer from the wine.ini file.
943 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
949 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
950 if (!buffer
[0]) return def
;
951 result
= strtol( buffer
, &p
, 0 );
952 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
956 /******************************************************************************
958 * int PROFILE_GetWineIniBool(
959 * char const *section,
960 * char const *key_name,
963 * Reads a boolean value from the wine.ini file. This function attempts to
964 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
965 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
966 * true. Anything else results in the return of the default value.
968 * This function uses 1 to indicate true, and 0 for false. You can check
969 * for existence by setting def to something other than 0 or 1 and
970 * examining the return value.
972 int PROFILE_GetWineIniBool(
974 char const *key_name
,
980 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
982 switch(key_value
[0]) {
1003 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section
, key_name
,
1004 def
? "TRUE" : "FALSE", key_value
[0],
1005 retval
? "TRUE" : "FALSE");
1011 /***********************************************************************
1012 * PROFILE_LoadWineIni
1014 * Load the old .winerc file.
1016 int PROFILE_LoadWineIni(void)
1018 OBJECT_ATTRIBUTES attr
;
1019 UNICODE_STRING nameW
;
1020 char buffer
[MAX_PATHNAME_LEN
];
1026 attr
.Length
= sizeof(attr
);
1027 attr
.RootDirectory
= 0;
1028 attr
.ObjectName
= &nameW
;
1029 attr
.Attributes
= 0;
1030 attr
.SecurityDescriptor
= NULL
;
1031 attr
.SecurityQualityOfService
= NULL
;
1033 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1034 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1035 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1037 ERR("Cannot create config registry key\n" );
1040 RtlFreeUnicodeString( &nameW
);
1043 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1044 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1045 NULL
, REG_OPTION_VOLATILE
, &disp
))
1047 ERR("Cannot create config registry key\n" );
1050 RtlFreeUnicodeString( &nameW
);
1052 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1054 if ((p
= getenv( "HOME" )) != NULL
)
1056 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1057 strcat( buffer
, PROFILE_WineIniName
);
1058 if ((f
= fopen( buffer
, "r" )) != NULL
)
1060 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1064 else WARN("could not get $HOME value for config file.\n" );
1066 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1068 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1073 if (disp
== REG_OPENED_EXISTING_KEY
)
1075 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1076 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed
);
1081 /* convert to the new format */
1082 sprintf( buffer
, "%s/config", get_config_dir() );
1083 convert_config( f
, buffer
);
1086 MESSAGE( "The '%s' configuration file has been converted\n"
1087 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1088 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1089 "and then remove the old one and restart Wine.\n" );
1094 /***********************************************************************
1095 * PROFILE_UsageWineIni
1097 * Explain the wine.ini file to those who don't read documentation.
1098 * Keep below one screenful in length so that error messages above are
1101 void PROFILE_UsageWineIni(void)
1103 MESSAGE("Perhaps you have not properly edited or created "
1104 "your Wine configuration file.\n");
1105 MESSAGE("This is '%s/config'\n", get_config_dir());
1106 /* RTFM, so to say */
1109 /***********************************************************************
1110 * PROFILE_GetStringItem
1112 * Convenience function that turns a string 'xxx, yyy, zzz' into
1113 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1115 char* PROFILE_GetStringItem( char* start
)
1119 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1123 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1125 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1127 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1130 if( lpch
) *lpch
= '\0';
1134 /********************* API functions **********************************/
1136 /***********************************************************************
1137 * GetProfileInt (KERNEL.57)
1139 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1141 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1145 /***********************************************************************
1146 * GetProfileIntA (KERNEL32.@)
1148 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1150 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1153 /***********************************************************************
1154 * GetProfileIntW (KERNEL32.@)
1156 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1158 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1162 * if allow_section_name_copy is TRUE, allow the copying :
1163 * - of Section names if 'section' is NULL
1164 * - of Keys in a Section if 'entry' is NULL
1165 * (see MSDN doc for GetPrivateProfileString)
1167 static int PROFILE_GetPrivateProfileString( LPCSTR section
, LPCSTR entry
,
1168 LPCSTR def_val
, LPSTR buffer
,
1169 UINT16 len
, LPCSTR filename
,
1170 BOOL allow_section_name_copy
)
1173 LPSTR pDefVal
= NULL
;
1176 filename
= "win.ini";
1178 /* strip any trailing ' ' of def_val. */
1181 LPSTR p
= (LPSTR
)&def_val
[strlen(def_val
)]; /* even "" works ! */
1189 if (*p
== ' ') /* ouch, contained trailing ' ' */
1191 int len
= (int)p
- (int)def_val
;
1192 pDefVal
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1193 strncpy(pDefVal
, def_val
, len
);
1194 pDefVal
[len
] = '\0';
1198 pDefVal
= (LPSTR
)def_val
;
1200 EnterCriticalSection( &PROFILE_CritSect
);
1202 if (PROFILE_Open( filename
)) {
1203 if ((allow_section_name_copy
) && (section
== NULL
))
1204 ret
= PROFILE_GetSectionNames(buffer
, len
);
1206 /* PROFILE_GetString already handles the 'entry == NULL' case */
1207 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1209 lstrcpynA( buffer
, pDefVal
, len
);
1210 ret
= strlen( buffer
);
1213 LeaveCriticalSection( &PROFILE_CritSect
);
1215 if (pDefVal
!= def_val
) /* allocated */
1216 HeapFree(GetProcessHeap(), 0, pDefVal
);
1221 /***********************************************************************
1222 * GetPrivateProfileString (KERNEL.128)
1224 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1225 LPCSTR def_val
, LPSTR buffer
,
1226 UINT16 len
, LPCSTR filename
)
1228 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1229 buffer
, len
, filename
, FALSE
);
1232 /***********************************************************************
1233 * GetPrivateProfileStringA (KERNEL32.@)
1235 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1236 LPCSTR def_val
, LPSTR buffer
,
1237 UINT len
, LPCSTR filename
)
1239 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1240 buffer
, len
, filename
, TRUE
);
1243 /***********************************************************************
1244 * GetPrivateProfileStringW (KERNEL32.@)
1246 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1247 LPCWSTR def_val
, LPWSTR buffer
,
1248 UINT len
, LPCWSTR filename
)
1250 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1251 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1252 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1253 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1254 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1255 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1256 bufferA
, len
, filenameA
);
1257 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1259 HeapFree( GetProcessHeap(), 0, sectionA
);
1260 HeapFree( GetProcessHeap(), 0, entryA
);
1261 HeapFree( GetProcessHeap(), 0, filenameA
);
1262 HeapFree( GetProcessHeap(), 0, def_valA
);
1263 HeapFree( GetProcessHeap(), 0, bufferA
);
1267 /***********************************************************************
1268 * GetProfileString (KERNEL.58)
1270 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1271 LPSTR buffer
, UINT16 len
)
1273 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1274 buffer
, len
, "win.ini", FALSE
);
1277 /***********************************************************************
1278 * GetProfileStringA (KERNEL32.@)
1280 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1281 LPSTR buffer
, UINT len
)
1283 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1284 buffer
, len
, "win.ini", TRUE
);
1287 /***********************************************************************
1288 * GetProfileStringW (KERNEL32.@)
1290 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1291 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1293 return GetPrivateProfileStringW( section
, entry
, def_val
,
1294 buffer
, len
, wininiW
);
1297 /***********************************************************************
1298 * WriteProfileString (KERNEL.59)
1300 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1303 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1306 /***********************************************************************
1307 * WriteProfileStringA (KERNEL32.@)
1309 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1312 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1315 /***********************************************************************
1316 * WriteProfileStringW (KERNEL32.@)
1318 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1321 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1325 /***********************************************************************
1326 * GetPrivateProfileInt (KERNEL.127)
1328 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1329 INT16 def_val
, LPCSTR filename
)
1331 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1333 if (result
> 65535) return 65535;
1334 if (result
>= 0) return (UINT16
)result
;
1335 if (result
< -32768) return -32768;
1336 return (UINT16
)(INT16
)result
;
1339 /***********************************************************************
1340 * GetPrivateProfileIntA (KERNEL32.@)
1342 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1343 INT def_val
, LPCSTR filename
)
1349 PROFILE_GetPrivateProfileString( section
, entry
, "",
1350 buffer
, sizeof(buffer
), filename
, FALSE
);
1351 if (!buffer
[0]) return (UINT
)def_val
;
1352 result
= strtol( buffer
, &p
, 0 );
1353 if (p
== buffer
) return 0; /* No digits at all */
1354 return (UINT
)result
;
1357 /***********************************************************************
1358 * GetPrivateProfileIntW (KERNEL32.@)
1360 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1361 INT def_val
, LPCWSTR filename
)
1363 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1364 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1365 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1366 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1367 HeapFree( GetProcessHeap(), 0, sectionA
);
1368 HeapFree( GetProcessHeap(), 0, filenameA
);
1369 HeapFree( GetProcessHeap(), 0, entryA
);
1373 /***********************************************************************
1374 * GetPrivateProfileSection (KERNEL.418)
1376 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1377 UINT16 len
, LPCSTR filename
)
1379 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1382 /***********************************************************************
1383 * GetPrivateProfileSectionA (KERNEL32.@)
1385 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1386 DWORD len
, LPCSTR filename
)
1390 EnterCriticalSection( &PROFILE_CritSect
);
1392 if (PROFILE_Open( filename
))
1393 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1396 LeaveCriticalSection( &PROFILE_CritSect
);
1401 /***********************************************************************
1402 * GetPrivateProfileSectionW (KERNEL32.@)
1405 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1406 DWORD len
, LPCWSTR filename
)
1409 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1410 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1411 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1412 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1414 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1415 HeapFree( GetProcessHeap(), 0, sectionA
);
1416 HeapFree( GetProcessHeap(), 0, filenameA
);
1417 HeapFree( GetProcessHeap(), 0, bufferA
);
1421 /***********************************************************************
1422 * GetProfileSection (KERNEL.419)
1424 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1426 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1429 /***********************************************************************
1430 * GetProfileSectionA (KERNEL32.@)
1432 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1434 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1437 /***********************************************************************
1438 * GetProfileSectionW (KERNEL32.@)
1440 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1442 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1446 /***********************************************************************
1447 * WritePrivateProfileString (KERNEL.129)
1449 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1450 LPCSTR string
, LPCSTR filename
)
1452 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1455 /***********************************************************************
1456 * WritePrivateProfileStringA (KERNEL32.@)
1458 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1459 LPCSTR string
, LPCSTR filename
)
1463 EnterCriticalSection( &PROFILE_CritSect
);
1465 if (PROFILE_Open( filename
))
1467 if (!section
&& !entry
&& !string
)
1468 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1470 ret
= PROFILE_SetString( section
, entry
, string
);
1473 LeaveCriticalSection( &PROFILE_CritSect
);
1477 /***********************************************************************
1478 * WritePrivateProfileStringW (KERNEL32.@)
1480 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1481 LPCWSTR string
, LPCWSTR filename
)
1483 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1484 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1485 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1486 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1487 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1488 stringA
, filenameA
);
1489 HeapFree( GetProcessHeap(), 0, sectionA
);
1490 HeapFree( GetProcessHeap(), 0, entryA
);
1491 HeapFree( GetProcessHeap(), 0, stringA
);
1492 HeapFree( GetProcessHeap(), 0, filenameA
);
1496 /***********************************************************************
1497 * WritePrivateProfileSection (KERNEL.416)
1499 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1500 LPCSTR string
, LPCSTR filename
)
1502 return WritePrivateProfileSectionA( section
, string
, filename
);
1505 /***********************************************************************
1506 * WritePrivateProfileSectionA (KERNEL32.@)
1508 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1509 LPCSTR string
, LPCSTR filename
)
1514 EnterCriticalSection( &PROFILE_CritSect
);
1516 if (PROFILE_Open( filename
)) {
1517 if (!section
&& !string
)
1518 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1519 else if (!string
) /* delete the named section*/
1520 ret
= PROFILE_SetString(section
,NULL
,NULL
);
1522 PROFILE_DeleteAllKeys(section
);
1525 LPSTR buf
= HeapAlloc( GetProcessHeap(), 0, strlen(string
)+1 );
1526 strcpy( buf
, string
);
1527 if((p
=strchr( buf
, '='))){
1529 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1532 HeapFree( GetProcessHeap(), 0, buf
);
1533 string
+= strlen(string
)+1;
1539 LeaveCriticalSection( &PROFILE_CritSect
);
1543 /***********************************************************************
1544 * WritePrivateProfileSectionW (KERNEL32.@)
1546 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1547 LPCWSTR string
, LPCWSTR filename
)
1550 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1551 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1552 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1553 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1554 HeapFree( GetProcessHeap(), 0, sectionA
);
1555 HeapFree( GetProcessHeap(), 0, stringA
);
1556 HeapFree( GetProcessHeap(), 0, filenameA
);
1560 /***********************************************************************
1561 * WriteProfileSection (KERNEL.417)
1563 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1565 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1568 /***********************************************************************
1569 * WriteProfileSectionA (KERNEL32.@)
1571 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1574 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1577 /***********************************************************************
1578 * WriteProfileSectionW (KERNEL32.@)
1580 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1582 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1585 /***********************************************************************
1586 * GetPrivateProfileSectionNames (KERNEL.143)
1588 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1593 EnterCriticalSection( &PROFILE_CritSect
);
1595 if (PROFILE_Open( filename
))
1596 ret
= PROFILE_GetSectionNames(buffer
, size
);
1598 LeaveCriticalSection( &PROFILE_CritSect
);
1604 /***********************************************************************
1605 * GetProfileSectionNames (KERNEL.142)
1607 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1610 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1614 /***********************************************************************
1615 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1617 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1621 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1625 /***********************************************************************
1626 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1628 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1632 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1633 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1635 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1636 if (size
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, size
))
1638 HeapFree( GetProcessHeap(), 0, bufferA
);
1639 HeapFree( GetProcessHeap(), 0, filenameA
);
1644 /***********************************************************************
1645 * GetPrivateProfileStruct (KERNEL.407)
1647 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1648 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1650 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1653 /***********************************************************************
1654 * GetPrivateProfileStructA (KERNEL32.@)
1656 * Should match Win95's behaviour pretty much
1658 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1659 LPVOID buf
, UINT len
, LPCSTR filename
)
1663 EnterCriticalSection( &PROFILE_CritSect
);
1665 if (PROFILE_Open( filename
)) {
1666 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1668 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1669 if (((strlen(k
->value
) - 2) / 2) == len
)
1676 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1677 /* check for invalid chars in ASCII coded hex string */
1678 for (p
=k
->value
; p
< end
; p
++)
1682 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1683 *p
, filename
, section
, key
);
1690 BOOL highnibble
= TRUE
;
1692 LPBYTE binbuf
= (LPBYTE
)buf
;
1694 end
-= 2; /* don't include checksum in output data */
1695 /* translate ASCII hex format into binary data */
1696 for (p
=k
->value
; p
< end
; p
++)
1700 (c
- 'A' + 10) : (c
- '0');
1707 *binbuf
++ = b
; /* feed binary data into output */
1708 chksum
+= b
; /* calculate checksum */
1710 highnibble
^= 1; /* toggle */
1712 /* retrieve stored checksum value */
1714 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1716 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1717 if (b
== (chksum
& 0xff)) /* checksums match ? */
1723 LeaveCriticalSection( &PROFILE_CritSect
);
1728 /***********************************************************************
1729 * GetPrivateProfileStructW (KERNEL32.@)
1731 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1732 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1734 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1735 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1736 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1737 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1739 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1741 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1742 ((LPWSTR
)buffer
)[len
-1] = 0;
1743 HeapFree( GetProcessHeap(), 0, bufferA
);
1744 HeapFree( GetProcessHeap(), 0, sectionA
);
1745 HeapFree( GetProcessHeap(), 0, keyA
);
1746 HeapFree( GetProcessHeap(), 0, filenameA
);
1753 /***********************************************************************
1754 * WritePrivateProfileStruct (KERNEL.406)
1756 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1757 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1759 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1762 /***********************************************************************
1763 * WritePrivateProfileStructA (KERNEL32.@)
1765 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1766 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1773 if (!section
&& !key
&& !buf
) /* flush the cache */
1774 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1776 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1777 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1779 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1780 *p
++ = hex
[*binbuf
>> 4];
1781 *p
++ = hex
[*binbuf
& 0xf];
1784 /* checksum is sum & 0xff */
1785 *p
++ = hex
[(sum
& 0xf0) >> 4];
1786 *p
++ = hex
[sum
& 0xf];
1789 EnterCriticalSection( &PROFILE_CritSect
);
1791 if (PROFILE_Open( filename
))
1792 ret
= PROFILE_SetString( section
, key
, outstring
);
1794 LeaveCriticalSection( &PROFILE_CritSect
);
1796 HeapFree( GetProcessHeap(), 0, outstring
);
1801 /***********************************************************************
1802 * WritePrivateProfileStructW (KERNEL32.@)
1804 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1805 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1807 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1808 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1809 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1810 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1812 HeapFree( GetProcessHeap(), 0, sectionA
);
1813 HeapFree( GetProcessHeap(), 0, keyA
);
1814 HeapFree( GetProcessHeap(), 0, filenameA
);
1820 /***********************************************************************
1821 * WriteOutProfiles (KERNEL.315)
1823 void WINAPI
WriteOutProfiles16(void)
1825 EnterCriticalSection( &PROFILE_CritSect
);
1826 PROFILE_FlushFile();
1827 LeaveCriticalSection( &PROFILE_CritSect
);
1830 /***********************************************************************
1831 * CloseProfileUserMapping (KERNEL32.@)
1833 BOOL WINAPI
CloseProfileUserMapping(void) {
1834 FIXME("(), stub!\n");
1835 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);