4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
13 #include <sys/types.h>
19 #include "wine/winbase16.h"
20 #include "wine/winestring.h"
26 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(profile
);
32 typedef struct tagPROFILEKEY
36 struct tagPROFILEKEY
*next
;
39 typedef struct tagPROFILESECTION
42 struct tagPROFILEKEY
*key
;
43 struct tagPROFILESECTION
*next
;
50 PROFILESECTION
*section
;
58 #define N_CACHED_PROFILES 10
60 /* Cached profile files */
61 static PROFILE
*MRUProfile
[N_CACHED_PROFILES
]={NULL
};
63 #define CurProfile (MRUProfile[0])
65 /* wine.ini config file registry root */
66 static HKEY wine_profile_key
;
68 #define PROFILE_MAX_LINE_LEN 1024
70 /* Wine profile name in $HOME directory; must begin with slash */
71 static const char PROFILE_WineIniName
[] = "/.winerc";
73 /* Wine profile: the profile file being used */
74 static char PROFILE_WineIniUsed
[MAX_PATHNAME_LEN
] = "";
76 /* Check for comments in profile */
77 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
79 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
81 static const WCHAR wininiW
[] = { 'w','i','n','.','i','n','i',0 };
83 static CRITICAL_SECTION PROFILE_CritSect
= CRITICAL_SECTION_INIT
;
85 static const char hex
[16] = "0123456789ABCDEF";
87 /***********************************************************************
90 * Copy the content of an entry into a buffer, removing quotes, and possibly
91 * translating environment variables.
93 static void PROFILE_CopyEntry( char *buffer
, const char *value
, int len
,
99 if ((*value
== '\'') || (*value
== '\"'))
101 if (value
[1] && (value
[strlen(value
)-1] == *value
)) quote
= *value
++;
106 lstrcpynA( buffer
, value
, len
);
107 if (quote
&& (len
>= strlen(value
))) buffer
[strlen(buffer
)-1] = '\0';
111 for (p
= value
; (*p
&& (len
> 1)); *buffer
++ = *p
++, len
-- )
113 if ((*p
== '$') && (p
[1] == '{'))
117 const char *p2
= strchr( p
, '}' );
118 if (!p2
) continue; /* ignore it */
119 lstrcpynA(env_val
, p
+ 2, min( sizeof(env_val
), (int)(p2
-p
)-1 ));
120 if ((env_p
= getenv( env_val
)) != NULL
)
122 lstrcpynA( buffer
, env_p
, len
);
123 buffer
+= strlen( buffer
);
124 len
-= strlen( buffer
);
129 if (quote
&& (len
> 1)) buffer
--;
134 /***********************************************************************
137 * Save a profile tree to a file.
139 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
143 for ( ; section
; section
= section
->next
)
145 if (section
->name
) fprintf( file
, "\r\n[%s]\r\n", section
->name
);
146 for (key
= section
->key
; key
; key
= key
->next
)
148 fprintf( file
, "%s", key
->name
);
149 if (key
->value
) fprintf( file
, "=%s", key
->value
);
150 fprintf( file
, "\r\n" );
156 /***********************************************************************
159 * Free a profile tree.
161 static void PROFILE_Free( PROFILESECTION
*section
)
163 PROFILESECTION
*next_section
;
164 PROFILEKEY
*key
, *next_key
;
166 for ( ; section
; section
= next_section
)
168 if (section
->name
) HeapFree( GetProcessHeap(), 0, section
->name
);
169 for (key
= section
->key
; key
; key
= next_key
)
171 next_key
= key
->next
;
172 if (key
->name
) HeapFree( GetProcessHeap(), 0, key
->name
);
173 if (key
->value
) HeapFree( GetProcessHeap(), 0, key
->value
);
174 HeapFree( GetProcessHeap(), 0, key
);
176 next_section
= section
->next
;
177 HeapFree( GetProcessHeap(), 0, section
);
181 static inline int PROFILE_isspace(char c
)
183 if (isspace(c
)) return 1;
184 if (c
=='\r' || c
==0x1a) return 1;
185 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
190 /***********************************************************************
193 * Load a profile tree from a file.
195 static PROFILESECTION
*PROFILE_Load( FILE *file
)
197 char buffer
[PROFILE_MAX_LINE_LEN
];
200 PROFILESECTION
*section
, *first_section
;
201 PROFILESECTION
**next_section
;
202 PROFILEKEY
*key
, *prev_key
, **next_key
;
204 first_section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
205 if(first_section
== NULL
) return NULL
;
206 first_section
->name
= NULL
;
207 first_section
->key
= NULL
;
208 first_section
->next
= NULL
;
209 next_section
= &first_section
->next
;
210 next_key
= &first_section
->key
;
213 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
217 while (*p
&& PROFILE_isspace(*p
)) p
++;
218 if (*p
== '[') /* section start */
220 if (!(p2
= strrchr( p
, ']' )))
222 WARN("Invalid section header at line %d: '%s'\n",
229 section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
230 if(section
== NULL
) break;
231 section
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
233 section
->next
= NULL
;
234 *next_section
= section
;
235 next_section
= §ion
->next
;
236 next_key
= §ion
->key
;
239 TRACE("New section: '%s'\n",section
->name
);
246 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
248 if ((p2
= strchr( p
, '=' )) != NULL
)
251 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
253 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
256 if(*p
|| !prev_key
|| *prev_key
->name
)
258 key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) );
259 if(key
== NULL
) break;
260 key
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
261 key
->value
= p2
? HEAP_strdupA( GetProcessHeap(), 0, p2
) : NULL
;
264 next_key
= &key
->next
;
267 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
270 return first_section
;
274 /***********************************************************************
275 * PROFILE_RegistryLoad
277 * Load a profile tree from a file into a registry key.
279 static DWORD
PROFILE_RegistryLoad( HKEY root
, FILE *file
)
283 char buffer
[PROFILE_MAX_LINE_LEN
];
287 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
291 while (*p
&& PROFILE_isspace(*p
)) p
++;
292 if (*p
== '[') /* section start */
294 if (!(p2
= strrchr( p
, ']' )))
296 WARN("Invalid section header at line %d: '%s'\n",
303 if (hkey
) RegCloseKey( hkey
);
304 if ((err
= RegCreateKeyExA( root
, p
, 0, NULL
, REG_OPTION_VOLATILE
,
305 KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))) return err
;
306 TRACE("New section: '%s'\n",p
);
312 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
314 if ((p2
= strchr( p
, '=' )) != NULL
)
317 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
319 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
322 if (*p
&& hkey
&& !IS_ENTRY_COMMENT(p
))
325 if ((err
= RegSetValueExA( hkey
, p
, 0, REG_SZ
, p2
, strlen(p2
)+1 )))
330 TRACE("New key: name='%s', value='%s'\n",p
,p2
);
333 if (hkey
) RegCloseKey( hkey
);
338 /***********************************************************************
339 * PROFILE_DeleteSection
341 * Delete a section from a profile tree.
343 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
347 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, name
))
349 PROFILESECTION
*to_del
= *section
;
350 *section
= to_del
->next
;
352 PROFILE_Free( to_del
);
355 section
= &(*section
)->next
;
361 /***********************************************************************
364 * Delete a key from a profile tree.
366 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
367 LPCSTR section_name
, LPCSTR key_name
)
371 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
373 PROFILEKEY
**key
= &(*section
)->key
;
376 if (!strcasecmp( (*key
)->name
, key_name
))
378 PROFILEKEY
*to_del
= *key
;
380 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
381 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
382 HeapFree( GetProcessHeap(), 0, to_del
);
388 section
= &(*section
)->next
;
394 /***********************************************************************
395 * PROFILE_DeleteAllKeys
397 * Delete all keys from a profile tree.
399 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
401 PROFILESECTION
**section
= &CurProfile
->section
;
404 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
406 PROFILEKEY
**key
= &(*section
)->key
;
409 PROFILEKEY
*to_del
= *key
;
411 if (to_del
->name
) HeapFree( GetProcessHeap(), 0, to_del
->name
);
412 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
413 HeapFree( GetProcessHeap(), 0, to_del
);
414 CurProfile
->changed
=TRUE
;
417 section
= &(*section
)->next
;
422 /***********************************************************************
425 * Find a key in a profile tree, optionally creating it.
427 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
,
428 const char *section_name
,
429 const char *key_name
, int create
)
434 while (PROFILE_isspace(*section_name
)) section_name
++;
435 p
= section_name
+ strlen(section_name
) - 1;
436 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
437 seclen
= p
- section_name
+ 1;
439 while (PROFILE_isspace(*key_name
)) key_name
++;
440 p
= key_name
+ strlen(key_name
) - 1;
441 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
442 keylen
= p
- key_name
+ 1;
446 if ( ((*section
)->name
)
447 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
448 && (((*section
)->name
)[seclen
] == '\0') )
450 PROFILEKEY
**key
= &(*section
)->key
;
453 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
454 && (((*key
)->name
)[keylen
] == '\0') )
458 if (!create
) return NULL
;
459 *key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
460 if(*key
== NULL
) return NULL
;
461 (*key
)->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
462 (*key
)->value
= NULL
;
466 section
= &(*section
)->next
;
468 if (!create
) return NULL
;
469 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) );
470 if(*section
== NULL
) return NULL
;
471 (*section
)->name
= HEAP_strdupA( GetProcessHeap(), 0, section_name
);
472 (*section
)->next
= NULL
;
473 (*section
)->key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) );
474 if((*section
)->key
== NULL
)
476 HeapFree(GetProcessHeap(), 0, *section
);
479 (*section
)->key
->name
= HEAP_strdupA( GetProcessHeap(), 0, key_name
);
480 (*section
)->key
->value
= NULL
;
481 (*section
)->key
->next
= NULL
;
482 return (*section
)->key
;
486 /***********************************************************************
489 * Flush the current profile to disk if changed.
491 static BOOL
PROFILE_FlushFile(void)
493 char *p
, buffer
[MAX_PATHNAME_LEN
];
494 const char *unix_name
;
500 WARN("No current profile!\n");
504 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
505 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
507 /* Try to create it in $HOME/.wine */
508 /* FIXME: this will need a more general solution */
509 strcpy( buffer
, get_config_dir() );
510 p
= buffer
+ strlen(buffer
);
512 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
514 file
= fopen( buffer
, "w" );
520 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
524 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
525 PROFILE_Save( file
, CurProfile
->section
);
527 CurProfile
->changed
= FALSE
;
528 if(!stat(unix_name
,&buf
))
529 CurProfile
->mtime
=buf
.st_mtime
;
534 /***********************************************************************
535 * PROFILE_ReleaseFile
537 * Flush the current profile to disk and remove it from the cache.
539 static void PROFILE_ReleaseFile(void)
542 PROFILE_Free( CurProfile
->section
);
543 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
544 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
545 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
546 CurProfile
->changed
= FALSE
;
547 CurProfile
->section
= NULL
;
548 CurProfile
->dos_name
= NULL
;
549 CurProfile
->unix_name
= NULL
;
550 CurProfile
->filename
= NULL
;
551 CurProfile
->mtime
= 0;
555 /***********************************************************************
558 * Open a profile file, checking the cached file first.
560 static BOOL
PROFILE_Open( LPCSTR filename
)
562 DOS_FULL_NAME full_name
;
563 char buffer
[MAX_PATHNAME_LEN
];
564 char *newdos_name
, *p
;
568 PROFILE
*tempProfile
;
570 /* First time around */
573 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
575 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
576 if(MRUProfile
[i
] == NULL
) break;
577 MRUProfile
[i
]->changed
=FALSE
;
578 MRUProfile
[i
]->section
=NULL
;
579 MRUProfile
[i
]->dos_name
=NULL
;
580 MRUProfile
[i
]->unix_name
=NULL
;
581 MRUProfile
[i
]->filename
=NULL
;
582 MRUProfile
[i
]->mtime
=0;
585 /* Check for a match */
587 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
588 strchr( filename
, ':' ))
590 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
594 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
595 strcat( buffer
, "\\" );
596 strcat( buffer
, filename
);
597 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
600 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
602 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
603 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
608 tempProfile
=MRUProfile
[i
];
610 MRUProfile
[j
]=MRUProfile
[j
-1];
611 CurProfile
=tempProfile
;
613 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
614 TRACE("(%s): already opened (mru=%d)\n",
617 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
623 /* Flush the old current profile */
626 /* Make the oldest profile the current one only in order to get rid of it */
627 if(i
==N_CACHED_PROFILES
)
629 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
630 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
631 MRUProfile
[i
]=MRUProfile
[i
-1];
632 CurProfile
=tempProfile
;
634 if(CurProfile
->filename
) PROFILE_ReleaseFile();
636 /* OK, now that CurProfile is definitely free we assign it our new file */
637 newdos_name
= HEAP_strdupA( GetProcessHeap(), 0, full_name
.short_name
);
638 CurProfile
->dos_name
= newdos_name
;
639 CurProfile
->filename
= HEAP_strdupA( GetProcessHeap(), 0, filename
);
641 /* Try to open the profile file, first in $HOME/.wine */
643 /* FIXME: this will need a more general solution */
644 strcpy( buffer
, get_config_dir() );
645 p
= buffer
+ strlen(buffer
);
647 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
649 if ((file
= fopen( buffer
, "r" )))
651 TRACE("(%s): found it in %s\n",
653 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
658 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0,
659 full_name
.long_name
);
660 if ((file
= fopen( full_name
.long_name
, "r" )))
661 TRACE("(%s): found it in %s\n",
662 filename
, full_name
.long_name
);
667 CurProfile
->section
= PROFILE_Load( file
);
669 if(!stat(CurProfile
->unix_name
,&buf
))
670 CurProfile
->mtime
=buf
.st_mtime
;
674 /* Does not exist yet, we will create it in PROFILE_FlushFile */
675 WARN("profile file %s not found\n", newdos_name
);
681 /***********************************************************************
684 * Returns all keys of a section.
685 * If return_values is TRUE, also include the corresponding values.
687 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
688 LPSTR buffer
, UINT len
, BOOL handle_env
,
694 if (section
->name
&& !strcasecmp( section
->name
, section_name
))
697 for (key
= section
->key
; key
; key
= key
->next
)
700 if (!*key
->name
) continue; /* Skip empty lines */
701 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
702 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
703 len
-= strlen(buffer
) + 1;
704 buffer
+= strlen(buffer
) + 1;
705 if (return_values
&& key
->value
) {
707 PROFILE_CopyEntry ( buffer
,
708 key
->value
, len
- 1, handle_env
);
709 len
-= strlen(buffer
) + 1;
710 buffer
+= strlen(buffer
) + 1;
715 /*If either lpszSection or lpszKey is NULL and the supplied
716 destination buffer is too small to hold all the strings,
717 the last string is truncated and followed by two null characters.
718 In this case, the return value is equal to cchReturnBuffer
726 section
= section
->next
;
728 buffer
[0] = buffer
[1] = '\0';
733 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
737 PROFILESECTION
*section
;
739 for (section
= CurProfile
->section
; section
; section
= section
->next
)
741 l
= strlen(section
->name
);
746 strcpy(buf
, section
->name
);
756 /***********************************************************************
759 * Get a profile string.
761 * Tests with GetPrivateProfileString16, W95a,
762 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
763 * section key_name def_val res buffer
764 * "set1" "1" "x" 43 [data]
765 * "set1" "1 " "x" 43 [data] (!)
766 * "set1" " 1 "' "x" 43 [data] (!)
767 * "set1" "" "x" 1 "x"
768 * "set1" "" "x " 1 "x" (!)
769 * "set1" "" " x " 3 " x" (!)
770 * "set1" NULL "x" 6 "1\02\03\0\0"
771 * "set1" "" "x" 1 "x"
772 * NULL "1" "x" 0 "" (!)
778 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
779 LPCSTR def_val
, LPSTR buffer
, UINT len
)
781 PROFILEKEY
*key
= NULL
;
783 if (!def_val
) def_val
= "";
784 if (key_name
&& key_name
[0])
786 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
);
787 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
789 TRACE("('%s','%s','%s'): returning '%s'\n",
790 section
, key_name
, def_val
, buffer
);
791 return strlen( buffer
);
793 if (key_name
&& !(key_name
[0]))
794 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
796 if (section
&& section
[0])
797 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
804 /***********************************************************************
807 * Set a profile string.
809 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
812 if (!key_name
) /* Delete a whole section */
814 TRACE("('%s')\n", section_name
);
815 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
817 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
818 this is not an error on application's level.*/
820 else if (!value
) /* Delete a key */
822 TRACE("('%s','%s')\n",
823 section_name
, key_name
);
824 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
825 section_name
, key_name
);
826 return TRUE
; /* same error handling as above */
828 else /* Set the key value */
830 PROFILEKEY
*key
= PROFILE_Find( &CurProfile
->section
, section_name
,
832 TRACE("('%s','%s','%s'): \n",
833 section_name
, key_name
, value
);
834 if (!key
) return FALSE
;
837 /* strip the leading spaces. We can safely strip \n\r and
838 * friends too, they should not happen here anyway. */
839 while (PROFILE_isspace(*value
)) value
++;
841 if (!strcmp( key
->value
, value
))
843 TRACE(" no change needed\n" );
844 return TRUE
; /* No change needed */
846 TRACE(" replacing '%s'\n", key
->value
);
847 HeapFree( GetProcessHeap(), 0, key
->value
);
849 else TRACE(" creating key\n" );
850 key
->value
= HEAP_strdupA( GetProcessHeap(), 0, value
);
851 CurProfile
->changed
= TRUE
;
857 /***********************************************************************
858 * PROFILE_GetWineIniString
860 * Get a config string from the wine.ini file.
862 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
863 const char *def
, char *buffer
, int len
)
865 char tmp
[PROFILE_MAX_LINE_LEN
];
869 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
872 DWORD count
= sizeof(tmp
);
873 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
876 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
877 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
878 return strlen(buffer
);
882 /***********************************************************************
883 * PROFILE_EnumWineIniString
885 * Get a config string from the wine.ini file.
887 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
888 char *name
, int name_len
, char *buffer
, int len
)
890 char tmp
[PROFILE_MAX_LINE_LEN
];
893 DWORD count
= sizeof(tmp
);
895 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
896 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
900 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
901 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
907 /***********************************************************************
908 * PROFILE_GetWineIniInt
910 * Get a config integer from the wine.ini file.
912 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
918 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
919 if (!buffer
[0]) return def
;
920 result
= strtol( buffer
, &p
, 0 );
921 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
925 /******************************************************************************
927 * int PROFILE_GetWineIniBool(
928 * char const *section,
929 * char const *key_name,
932 * Reads a boolean value from the wine.ini file. This function attempts to
933 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
934 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
935 * true. Anything else results in the return of the default value.
937 * This function uses 1 to indicate true, and 0 for false. You can check
938 * for existence by setting def to something other than 0 or 1 and
939 * examining the return value.
941 int PROFILE_GetWineIniBool(
943 char const *key_name
,
949 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
951 switch(key_value
[0]) {
972 TRACE("(\"%s\", \"%s\", %s), "
973 "[%c], ret %s.\n", section
, key_name
,
974 def
? "TRUE" : "FALSE", key_value
[0],
975 retval
? "TRUE" : "FALSE");
981 /***********************************************************************
982 * PROFILE_LoadWineIni
984 * Load the wine.ini file.
986 int PROFILE_LoadWineIni(void)
988 char buffer
[MAX_PATHNAME_LEN
];
994 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
995 if (RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine", &hKeySW
))
997 ERR("Cannot create config registry key\n" );
1000 RegCloseKey( hKeySW
);
1001 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config", 0, NULL
,
1002 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &wine_profile_key
, &disp
))
1004 ERR("Cannot create config registry key\n" );
1008 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1010 if ( (Options
.configFileName
!=NULL
) && (f
= fopen(Options
.configFileName
, "r")) )
1012 /* Open -config specified file */
1013 lstrcpynA(PROFILE_WineIniUsed
,Options
.configFileName
,MAX_PATHNAME_LEN
);
1017 if ( (p
= getenv( "WINE_INI" )) && (f
= fopen( p
, "r" )) )
1019 lstrcpynA(PROFILE_WineIniUsed
,p
,MAX_PATHNAME_LEN
);
1022 if ((p
= getenv( "HOME" )) != NULL
)
1024 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1025 strcat( buffer
, PROFILE_WineIniName
);
1026 if ((f
= fopen( buffer
, "r" )) != NULL
)
1028 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1032 else WARN("could not get $HOME value for config file.\n" );
1034 /* Try global file */
1036 if ((f
= fopen( WINE_INI_GLOBAL
, "r" )) != NULL
)
1038 lstrcpynA(PROFILE_WineIniUsed
,WINE_INI_GLOBAL
,MAX_PATHNAME_LEN
);
1042 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1044 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1045 WINE_INI_GLOBAL
, PROFILE_WineIniName
);
1050 if (disp
== REG_OPENED_EXISTING_KEY
)
1052 MESSAGE( "Warning: configuration loaded by the server from %s/config,\n"
1053 " file %s was ignored.\n", get_config_dir(), PROFILE_WineIniUsed
);
1058 PROFILE_RegistryLoad( wine_profile_key
, f
);
1064 /***********************************************************************
1065 * PROFILE_UsageWineIni
1067 * Explain the wine.ini file to those who don't read documentation.
1068 * Keep below one screenful in length so that error messages above are
1071 void PROFILE_UsageWineIni(void)
1073 MESSAGE("Perhaps you have not properly edited or created "
1074 "your Wine configuration file.\n");
1075 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL
,PROFILE_WineIniName
);
1076 MESSAGE(" or it is determined by the -config option or from\n"
1077 " the WINE_INI environment variable.\n");
1078 if (*PROFILE_WineIniUsed
)
1079 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed
);
1080 /* RTFM, so to say */
1083 /***********************************************************************
1084 * PROFILE_GetStringItem
1086 * Convenience function that turns a string 'xxx, yyy, zzz' into
1087 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1089 char* PROFILE_GetStringItem( char* start
)
1093 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1097 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1099 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1101 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1104 if( lpch
) *lpch
= '\0';
1108 /********************* API functions **********************************/
1110 /***********************************************************************
1111 * GetProfileInt16 (KERNEL.57)
1113 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1115 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1119 /***********************************************************************
1120 * GetProfileIntA (KERNEL32.264)
1122 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1124 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1127 /***********************************************************************
1128 * GetProfileIntW (KERNEL32.264)
1130 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1132 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1136 * undoc_feature means:
1137 * return section names string list if both section and entry are NULL.
1139 static int PROFILE_GetPrivateProfileString( LPCSTR section
, LPCSTR entry
,
1140 LPCSTR def_val
, LPSTR buffer
,
1141 UINT16 len
, LPCSTR filename
,
1142 BOOL undoc_feature
)
1145 LPSTR pDefVal
= NULL
;
1148 filename
= "win.ini";
1150 /* strip any trailing ' ' of def_val. */
1153 LPSTR p
= (LPSTR
)&def_val
[strlen(def_val
)]; /* even "" works ! */
1161 if (*p
== ' ') /* ouch, contained trailing ' ' */
1163 int len
= (int)p
- (int)def_val
;
1164 pDefVal
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1165 strncpy(pDefVal
, def_val
, len
);
1166 pDefVal
[len
] = '\0';
1170 pDefVal
= (LPSTR
)def_val
;
1172 EnterCriticalSection( &PROFILE_CritSect
);
1174 if (PROFILE_Open( filename
)) {
1175 if ((undoc_feature
) && (section
== NULL
) && (entry
== NULL
))
1176 /* undocumented; both section and entry are NULL */
1177 ret
= PROFILE_GetSectionNames(buffer
, len
);
1179 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1181 lstrcpynA( buffer
, pDefVal
, len
);
1182 ret
= strlen( buffer
);
1185 LeaveCriticalSection( &PROFILE_CritSect
);
1187 if (pDefVal
!= def_val
) /* allocated */
1188 HeapFree(GetProcessHeap(), 0, pDefVal
);
1193 /***********************************************************************
1194 * GetPrivateProfileString16 (KERNEL.128)
1196 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1197 LPCSTR def_val
, LPSTR buffer
,
1198 UINT16 len
, LPCSTR filename
)
1200 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1201 buffer
, len
, filename
, FALSE
);
1204 /***********************************************************************
1205 * GetPrivateProfileStringA (KERNEL32.255)
1207 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1208 LPCSTR def_val
, LPSTR buffer
,
1209 UINT len
, LPCSTR filename
)
1211 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1212 buffer
, len
, filename
, TRUE
);
1215 /***********************************************************************
1216 * GetPrivateProfileStringW (KERNEL32.256)
1218 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1219 LPCWSTR def_val
, LPWSTR buffer
,
1220 UINT len
, LPCWSTR filename
)
1222 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1223 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1224 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1225 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1226 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1227 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1228 bufferA
, len
, filenameA
);
1229 lstrcpynAtoW( buffer
, bufferA
, len
);
1230 HeapFree( GetProcessHeap(), 0, sectionA
);
1231 HeapFree( GetProcessHeap(), 0, entryA
);
1232 HeapFree( GetProcessHeap(), 0, filenameA
);
1233 HeapFree( GetProcessHeap(), 0, def_valA
);
1234 HeapFree( GetProcessHeap(), 0, bufferA
);
1238 /***********************************************************************
1239 * GetProfileString16 (KERNEL.58)
1241 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1242 LPSTR buffer
, UINT16 len
)
1244 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1245 buffer
, len
, "win.ini", FALSE
);
1248 /***********************************************************************
1249 * GetProfileStringA (KERNEL32.268)
1251 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1252 LPSTR buffer
, UINT len
)
1254 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1255 buffer
, len
, "win.ini", TRUE
);
1258 /***********************************************************************
1259 * GetProfileStringW (KERNEL32.269)
1261 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1262 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1264 return GetPrivateProfileStringW( section
, entry
, def_val
,
1265 buffer
, len
, wininiW
);
1268 /***********************************************************************
1269 * WriteProfileString16 (KERNEL.59)
1271 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1274 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1277 /***********************************************************************
1278 * WriteProfileStringA (KERNEL32.587)
1280 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1283 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1286 /***********************************************************************
1287 * WriteProfileStringW (KERNEL32.588)
1289 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1292 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1296 /***********************************************************************
1297 * GetPrivateProfileInt16 (KERNEL.127)
1299 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1300 INT16 def_val
, LPCSTR filename
)
1302 long result
=(long)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1304 if (result
> 65535) return 65535;
1305 if (result
>= 0) return (UINT16
)result
;
1306 if (result
< -32768) return -32768;
1307 return (UINT16
)(INT16
)result
;
1310 /***********************************************************************
1311 * GetPrivateProfileIntA (KERNEL32.251)
1313 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1314 INT def_val
, LPCSTR filename
)
1320 PROFILE_GetPrivateProfileString( section
, entry
, "",
1321 buffer
, sizeof(buffer
), filename
, FALSE
);
1322 if (!buffer
[0]) return (UINT
)def_val
;
1323 result
= strtol( buffer
, &p
, 0 );
1324 if (p
== buffer
) return 0; /* No digits at all */
1325 return (UINT
)result
;
1328 /***********************************************************************
1329 * GetPrivateProfileIntW (KERNEL32.252)
1331 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1332 INT def_val
, LPCWSTR filename
)
1334 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1335 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1336 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1337 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1338 HeapFree( GetProcessHeap(), 0, sectionA
);
1339 HeapFree( GetProcessHeap(), 0, filenameA
);
1340 HeapFree( GetProcessHeap(), 0, entryA
);
1344 /***********************************************************************
1345 * GetPrivateProfileSection16 (KERNEL.418)
1347 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1348 UINT16 len
, LPCSTR filename
)
1350 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1353 /***********************************************************************
1354 * GetPrivateProfileSectionA (KERNEL32.255)
1356 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1357 DWORD len
, LPCSTR filename
)
1361 EnterCriticalSection( &PROFILE_CritSect
);
1363 if (PROFILE_Open( filename
))
1364 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1367 LeaveCriticalSection( &PROFILE_CritSect
);
1372 /***********************************************************************
1373 * GetPrivateProfileSectionW (KERNEL32.256)
1376 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1377 DWORD len
, LPCWSTR filename
)
1380 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1381 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1382 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1383 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1385 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1386 HeapFree( GetProcessHeap(), 0, sectionA
);
1387 HeapFree( GetProcessHeap(), 0, filenameA
);
1388 HeapFree( GetProcessHeap(), 0, bufferA
);
1392 /***********************************************************************
1393 * GetProfileSection16 (KERNEL.419)
1395 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1397 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1400 /***********************************************************************
1401 * GetProfileSectionA (KERNEL32.268)
1403 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1405 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1408 /***********************************************************************
1409 * GetProfileSectionW (KERNEL32)
1411 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1413 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1417 /***********************************************************************
1418 * WritePrivateProfileString16 (KERNEL.129)
1420 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1421 LPCSTR string
, LPCSTR filename
)
1423 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1426 /***********************************************************************
1427 * WritePrivateProfileStringA (KERNEL32.582)
1429 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1430 LPCSTR string
, LPCSTR filename
)
1434 EnterCriticalSection( &PROFILE_CritSect
);
1436 if (PROFILE_Open( filename
))
1438 if (!section
&& !entry
&& !string
)
1439 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1441 ret
= PROFILE_SetString( section
, entry
, string
);
1444 LeaveCriticalSection( &PROFILE_CritSect
);
1448 /***********************************************************************
1449 * WritePrivateProfileStringW (KERNEL32.583)
1451 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1452 LPCWSTR string
, LPCWSTR filename
)
1454 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1455 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1456 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1457 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1458 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1459 stringA
, filenameA
);
1460 HeapFree( GetProcessHeap(), 0, sectionA
);
1461 HeapFree( GetProcessHeap(), 0, entryA
);
1462 HeapFree( GetProcessHeap(), 0, stringA
);
1463 HeapFree( GetProcessHeap(), 0, filenameA
);
1467 /***********************************************************************
1468 * WritePrivateProfileSection16 (KERNEL.416)
1470 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1471 LPCSTR string
, LPCSTR filename
)
1473 return WritePrivateProfileSectionA( section
, string
, filename
);
1476 /***********************************************************************
1477 * WritePrivateProfileSectionA (KERNEL32)
1479 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1480 LPCSTR string
, LPCSTR filename
)
1485 EnterCriticalSection( &PROFILE_CritSect
);
1487 if (PROFILE_Open( filename
)) {
1488 if (!section
&& !string
&& !filename
)
1489 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1490 else if (!string
) /* delete the named section*/
1491 ret
= PROFILE_SetString(section
,NULL
,NULL
);
1493 PROFILE_DeleteAllKeys(section
);
1496 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1497 if((p
=strchr( buf
, '='))){
1499 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1502 HeapFree( GetProcessHeap(), 0, buf
);
1503 string
+= strlen(string
)+1;
1509 LeaveCriticalSection( &PROFILE_CritSect
);
1513 /***********************************************************************
1514 * WritePrivateProfileSectionW (KERNEL32)
1516 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1517 LPCWSTR string
, LPCWSTR filename
)
1520 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1521 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1522 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1523 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1524 HeapFree( GetProcessHeap(), 0, sectionA
);
1525 HeapFree( GetProcessHeap(), 0, stringA
);
1526 HeapFree( GetProcessHeap(), 0, filenameA
);
1530 /***********************************************************************
1531 * WriteProfileSection16 (KERNEL.417)
1533 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1535 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1538 /***********************************************************************
1539 * WriteProfileSectionA (KERNEL32.747)
1541 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1544 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1547 /***********************************************************************
1548 * WriteProfileSectionW (KERNEL32.748)
1550 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1552 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1555 /***********************************************************************
1556 * GetPrivateProfileSectionNames16 (KERNEL.143)
1558 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1563 EnterCriticalSection( &PROFILE_CritSect
);
1565 if (PROFILE_Open( filename
))
1566 ret
= PROFILE_GetSectionNames(buffer
, size
);
1568 LeaveCriticalSection( &PROFILE_CritSect
);
1574 /***********************************************************************
1575 * GetProfileSectionNames16 (KERNEL.142)
1577 WORD WINAPI
GetProfileSectionNames16( LPSTR buffer
, WORD size
)
1580 return (GetPrivateProfileSectionNames16 (buffer
,size
,"win.ini"));
1584 /***********************************************************************
1585 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1587 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1591 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1595 /***********************************************************************
1596 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1598 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1602 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1603 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1605 INT ret
= GetPrivateProfileSectionNames16 (bufferA
, size
, filenameA
);
1606 lstrcpynAtoW( buffer
, bufferA
, size
);
1607 HeapFree( GetProcessHeap(), 0, bufferA
);
1608 HeapFree( GetProcessHeap(), 0, filenameA
);
1613 /***********************************************************************
1614 * GetPrivateProfileStruct16 (KERNEL.407)
1616 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1617 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1619 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1622 /***********************************************************************
1623 * GetPrivateProfileStructA (KERNEL32.370)
1625 * Should match Win95's behaviour pretty much
1627 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1628 LPVOID buf
, UINT len
, LPCSTR filename
)
1632 EnterCriticalSection( &PROFILE_CritSect
);
1634 if (PROFILE_Open( filename
)) {
1635 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1637 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1638 if (((strlen(k
->value
) - 2) / 2) == len
)
1645 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1646 /* check for invalid chars in ASCII coded hex string */
1647 for (p
=k
->value
; p
< end
; p
++)
1651 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1652 *p
, filename
, section
, key
);
1659 BOOL highnibble
= TRUE
;
1661 LPBYTE binbuf
= (LPBYTE
)buf
;
1663 end
-= 2; /* don't include checksum in output data */
1664 /* translate ASCII hex format into binary data */
1665 for (p
=k
->value
; p
< end
; p
++)
1669 (c
- 'A' + 10) : (c
- '0');
1676 *binbuf
++ = b
; /* feed binary data into output */
1677 chksum
+= b
; /* calculate checksum */
1679 highnibble
^= 1; /* toggle */
1681 /* retrieve stored checksum value */
1683 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1685 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1686 if (b
== (chksum
& 0xff)) /* checksums match ? */
1692 LeaveCriticalSection( &PROFILE_CritSect
);
1697 /***********************************************************************
1698 * GetPrivateProfileStructW (KERNEL32.543)
1700 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1701 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1703 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1704 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1705 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1706 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1708 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1710 lstrcpynAtoW( buffer
, bufferA
, len
);
1711 HeapFree( GetProcessHeap(), 0, bufferA
);
1712 HeapFree( GetProcessHeap(), 0, sectionA
);
1713 HeapFree( GetProcessHeap(), 0, keyA
);
1714 HeapFree( GetProcessHeap(), 0, filenameA
);
1721 /***********************************************************************
1722 * WritePrivateProfileStruct16 (KERNEL.406)
1724 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1725 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1727 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1730 /***********************************************************************
1731 * WritePrivateProfileStructA (KERNEL32.744)
1733 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1734 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1741 if (!section
&& !key
&& !buf
) /* flush the cache */
1742 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1744 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1745 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1747 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1748 *p
++ = hex
[*binbuf
>> 4];
1749 *p
++ = hex
[*binbuf
& 0xf];
1752 /* checksum is sum & 0xff */
1753 *p
++ = hex
[(sum
& 0xf0) >> 4];
1754 *p
++ = hex
[sum
& 0xf];
1757 EnterCriticalSection( &PROFILE_CritSect
);
1759 if (PROFILE_Open( filename
))
1760 ret
= PROFILE_SetString( section
, key
, outstring
);
1762 LeaveCriticalSection( &PROFILE_CritSect
);
1764 HeapFree( GetProcessHeap(), 0, outstring
);
1769 /***********************************************************************
1770 * WritePrivateProfileStructW (KERNEL32.544)
1772 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1773 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1775 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1776 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1777 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1778 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1780 HeapFree( GetProcessHeap(), 0, sectionA
);
1781 HeapFree( GetProcessHeap(), 0, keyA
);
1782 HeapFree( GetProcessHeap(), 0, filenameA
);
1788 /***********************************************************************
1789 * WriteOutProfiles (KERNEL.315)
1791 void WINAPI
WriteOutProfiles16(void)
1793 EnterCriticalSection( &PROFILE_CritSect
);
1794 PROFILE_FlushFile();
1795 LeaveCriticalSection( &PROFILE_CritSect
);
1798 /***********************************************************************
1799 * CloseProfileUserMapping (KERNEL.138)
1801 BOOL WINAPI
CloseProfileUserMapping(void) {
1802 FIXME("(), stub!\n");
1803 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);