source: trunk/src/kernel32/profile.cpp@ 565

Last change on this file since 565 was 565, checked in by phaller, 26 years ago

Fix: bugfix in profile.cpp (flushing profile)

File size: 43.3 KB
Line 
1/* $Id: profile.cpp,v 1.17 1999-08-18 23:44:48 phaller Exp $ */
2
3/*
4 * Project Odin Software License can be found in LICENSE.TXT
5 *
6 * Win32 profile API functions
7 *
8 * Copyright 1993 Miguel de Icaza
9 * Copyright 1996 Alexandre Julliard
10 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
11 * Copyright 1998 Patrick Haller
12 * Copyright 1999 Christoph Bratschi
13 */
14
15#include <os2win.h>
16#include <ctype.h>
17#include <stdlib.h>
18#include <string.h>
19#include <stdio.h>
20#include <unicode.h>
21#include "heap.h"
22#include "heapstring.h"
23
24#include <sys/stat.h>
25
26#include "winbase.h"
27//#include "wine/winbase16.h"
28#include "winuser.h"
29#include "winnls.h"
30
31
32// -------------------------
33// WINE compatibility macros
34// -------------------------
35
36#ifndef MAX_PATHNAME_LEN
37#define MAX_PATHNAME_LEN 260
38#endif
39
40#define SystemHeap GetProcessHeap()
41#define strcasecmp strcmp
42#define DOSFS_GetFullName(a,b,c) strcpy(c,a)
43//#define lstrcpynA(a,b,c) strncpy((char*)a,(char*)b,(int)c)
44#define CharLowerA(a) (a)
45
46
47typedef struct tagPROFILEKEY
48{
49 char *name;
50 char *value;
51 struct tagPROFILEKEY *next;
52} PROFILEKEY;
53
54typedef struct tagPROFILESECTION
55{
56 char *name;
57 struct tagPROFILEKEY *key;
58 struct tagPROFILESECTION *next;
59} PROFILESECTION;
60
61
62typedef struct
63{
64 BOOL changed;
65 PROFILESECTION *section;
66 char *filename; //first open name
67 char *fullname; //name with path
68 time_t mtime;
69} PROFILE;
70
71
72#define N_CACHED_PROFILES 10
73
74/* Cached profile files */
75static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
76
77#define CurProfile (MRUProfile[0])
78
79/* wine.ini profile content */
80static PROFILESECTION *PROFILE_WineProfile;
81
82#define PROFILE_MAX_LINE_LEN 1024
83#define WINININAME "WIN.INI"
84
85/* Wine profile name in $HOME directory; must begin with slash */
86static const char PROFILE_WineIniName[] = "/.winerc";
87
88/* Wine profile: the profile file being used */
89static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
90
91/* Check for comments in profile */
92#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
93
94#define WINE_INI_GLOBAL ETCDIR "/wine.conf"
95
96static LPCWSTR wininiW = NULL; //CB: never freed
97
98static CRITICAL_SECTION PROFILE_CritSect;
99
100
101/***********************************************************************
102 * PROFILE_CopyEntry
103 *
104 * Copy the content of an entry into a buffer, removing quotes, and possibly
105 * translating environment variables.
106 */
107static void PROFILE_CopyEntry( char *buffer,
108 const char *value,
109 int len,
110 int handle_env )
111{
112 char quote = '\0';
113 const char *p;
114
115 if ((*value == '\'') || (*value == '\"'))
116 {
117 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
118 }
119
120 if (!handle_env)
121 {
122 lstrcpynA( buffer, value, len );
123 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
124 return;
125 }
126
127 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
128 {
129 if ((*p == '$') && (p[1] == '{'))
130 {
131 char env_val[1024];
132 const char *env_p;
133 const char *p2 = strchr( p, '}' );
134 if (!p2) continue; /* ignore it */
135 lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
136 if ((env_p = getenv( env_val )) != NULL)
137 {
138 lstrcpynA( buffer, env_p, len );
139 buffer += strlen( buffer );
140 len -= strlen( buffer );
141 }
142 p = p2 + 1;
143 }
144 }
145 *buffer = '\0';
146}
147
148
149/***********************************************************************
150 * PROFILE_Save
151 *
152 * Save a profile tree to a file.
153 */
154static void PROFILE_Save( FILE *file, PROFILESECTION *section )
155{
156 PROFILEKEY *key;
157
158 for ( ; section; section = section->next)
159 {
160 if (section->name) fprintf( file, "\n[%s]\n", section->name );
161 for (key = section->key; key; key = key->next)
162 {
163 fprintf( file, "%s", key->name );
164 if (key->value) fprintf( file, "=%s", key->value );
165 fprintf( file, "\n" );
166 }
167 }
168}
169
170
171/***********************************************************************
172 * PROFILE_Free
173 *
174 * Free a profile tree.
175 */
176static void PROFILE_Free( PROFILESECTION *section )
177{
178 PROFILESECTION *next_section;
179 PROFILEKEY *key, *next_key;
180
181 for ( ; section; section = next_section)
182 {
183 if (section->name) HeapFree( SystemHeap, 0, section->name );
184 for (key = section->key; key; key = next_key)
185 {
186 next_key = key->next;
187 if (key->name) HeapFree( SystemHeap, 0, key->name );
188 if (key->value) HeapFree( SystemHeap, 0, key->value );
189 HeapFree( SystemHeap, 0, key );
190 }
191 next_section = section->next;
192 HeapFree( SystemHeap, 0, section );
193 }
194}
195
196static int
197PROFILE_isspace(char c) {
198 if (isspace(c)) return 1;
199 if (c=='\r' || c==0x1a) return 1;
200 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
201 return 0;
202}
203
204
205/***********************************************************************
206 * PROFILE_Load
207 *
208 * Load a profile tree from a file.
209 */
210static PROFILESECTION *PROFILE_Load( FILE *file )
211{
212 char buffer[PROFILE_MAX_LINE_LEN];
213 char *p, *p2;
214 int line = 0;
215 PROFILESECTION *section, *first_section;
216 PROFILESECTION **next_section;
217 PROFILEKEY *key, *prev_key, **next_key;
218
219 first_section = (PROFILESECTION *)HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
220 first_section->name = NULL;
221 first_section->key = NULL;
222 first_section->next = NULL;
223 next_section = &first_section->next;
224 next_key = &first_section->key;
225 prev_key = NULL;
226
227 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
228 {
229 line++;
230 p = buffer;
231 while (*p && PROFILE_isspace(*p)) p++;
232 if (*p == '[') /* section start */
233 {
234 if (!(p2 = strrchr( p, ']' )))
235 {
236 dprintf(("Kernel32:Profile:Invalid section header at line %d: '%s'\n",
237 line, p ));
238 }
239 else
240 {
241 *p2 = '\0';
242 p++;
243 section = (PROFILESECTION*)HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
244 section->name = HEAP_strdupA( SystemHeap, 0, p );
245 section->key = NULL;
246 section->next = NULL;
247 *next_section = section;
248 next_section = &section->next;
249 next_key = &section->key;
250 prev_key = NULL;
251
252 dprintf(("Kernel32:Profile:New section: '%s'\n",section->name));
253
254 continue;
255 }
256 }
257
258 p2=p+strlen(p) - 1;
259 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
260
261 if ((p2 = strchr( p, '=' )) != NULL)
262 {
263 char *p3 = p2 - 1;
264 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
265 *p2++ = '\0';
266 while (*p2 && PROFILE_isspace(*p2)) p2++;
267 }
268
269 if(*p || !prev_key || *prev_key->name)
270 {
271 key = (PROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
272 key->name = HEAP_strdupA( SystemHeap, 0, p );
273 key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
274 key->next = NULL;
275 *next_key = key;
276 next_key = &key->next;
277 prev_key = key;
278
279 dprintf(("Kernel32:Profile:New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)"));
280 }
281 }
282 return first_section;
283}
284
285
286/***********************************************************************
287 * PROFILE_DeleteSection
288 *
289 * Delete a section from a profile tree.
290 */
291static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
292{
293 while (*section)
294 {
295 if ((*section)->name && !strcasecmp( (*section)->name, name ))
296 {
297 PROFILESECTION *to_del = *section;
298 *section = to_del->next;
299 to_del->next = NULL;
300 PROFILE_Free( to_del );
301 return TRUE;
302 }
303 section = &(*section)->next;
304 }
305 return FALSE;
306}
307
308
309/***********************************************************************
310 * PROFILE_DeleteKey
311 *
312 * Delete a key from a profile tree.
313 */
314static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
315 LPCSTR section_name, LPCSTR key_name )
316{
317 while (*section)
318 {
319 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
320 {
321 PROFILEKEY **key = &(*section)->key;
322 while (*key)
323 {
324 if (!strcasecmp( (*key)->name, key_name ))
325 {
326 PROFILEKEY *to_del = *key;
327 *key = to_del->next;
328 if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
329 if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
330 HeapFree( SystemHeap, 0, to_del );
331 return TRUE;
332 }
333 key = &(*key)->next;
334 }
335 }
336 section = &(*section)->next;
337 }
338 return FALSE;
339}
340
341
342/***********************************************************************
343 * PROFILE_Find
344 *
345 * Find a key in a profile tree, optionally creating it.
346 */
347static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
348 const char *section_name,
349 const char *key_name, int create )
350{
351 while (*section)
352 {
353 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
354 {
355 PROFILEKEY **key = &(*section)->key;
356 while (*key)
357 {
358 if (!strcasecmp( (*key)->name, key_name )) return *key;
359 key = &(*key)->next;
360 }
361 if (!create) return NULL;
362 *key = (PROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
363 (*key)->name = HEAP_strdupA( SystemHeap, 0, key_name );
364 (*key)->value = NULL;
365 (*key)->next = NULL;
366 return *key;
367 }
368 section = &(*section)->next;
369 }
370 if (!create) return NULL;
371 *section = (PROFILESECTION*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
372 (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
373 (*section)->next = NULL;
374 (*section)->key = (tagPROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
375 (*section)->key->name = HEAP_strdupA( SystemHeap, 0, key_name );
376 (*section)->key->value = NULL;
377 (*section)->key->next = NULL;
378 return (*section)->key;
379}
380
381
382/***********************************************************************
383 * PROFILE_FlushFile
384 *
385 * Flush the current profile to disk if changed.
386 */
387static BOOL PROFILE_FlushFile(void)
388{
389 FILE *file = NULL;
390 struct stat buf;
391
392 if(!CurProfile)
393 {
394 dprintf(("Kernel32:Profile:No current profile!\n"));
395 return FALSE;
396 }
397
398 // not changed, return immediately
399 if (!CurProfile->changed)
400 return TRUE;
401
402 // try to open file
403 file = fopen(CurProfile->fullname, "w");
404 if (!file)
405 {
406 dprintf(("Kernel32:Profile:could not save profile file %s\n", CurProfile->fullname));
407 return FALSE;
408 }
409
410 dprintf(("Kernel32:Profile:Saving %s\n", CurProfile->fullname ));
411 PROFILE_Save( file, CurProfile->section );
412 fclose( file );
413 CurProfile->changed = FALSE;
414 if(!stat(CurProfile->fullname,&buf))
415 CurProfile->mtime=buf.st_mtime;
416 return TRUE;
417}
418
419
420/***********************************************************************
421 * PROFILE_ReleaseFile
422 *
423 * Flush the current profile to disk and remove it from the cache.
424 */
425static void PROFILE_ReleaseFile(void)
426{
427 PROFILE_FlushFile();
428 PROFILE_Free( CurProfile->section );
429 if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
430 if (CurProfile->fullname) HeapFree(SystemHeap,0,CurProfile->fullname);
431 CurProfile->changed = FALSE;
432 CurProfile->section = NULL;
433 CurProfile->filename = NULL;
434 CurProfile->fullname = NULL;
435 CurProfile->mtime = 0;
436}
437
438
439/***********************************************************************
440 * PROFILE_Open
441 *
442 * Open a profile file, checking the cached file first.
443 */
444static BOOL PROFILE_Open( LPCSTR filename )
445{
446 FILE *file = NULL;
447 int i,j;
448 struct stat buf;
449 PROFILE *tempProfile;
450
451 if (!filename || filename[0] == 0) return FALSE;
452
453 /* First time around */
454
455 if(!CurProfile)
456 for(i=0;i<N_CACHED_PROFILES;i++)
457 {
458 MRUProfile[i]= (PROFILE*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
459 MRUProfile[i]->changed=FALSE;
460 MRUProfile[i]->section=NULL;
461 MRUProfile[i]->filename=NULL;
462 MRUProfile[i]->fullname=NULL;
463 MRUProfile[i]->mtime=0;
464 }
465
466 /* Check for a match */
467
468 for(i=0;i<N_CACHED_PROFILES;i++)
469 {
470 if (MRUProfile[i]->filename && (!strcmp(filename,MRUProfile[i]->filename) || !strcmp(filename,MRUProfile[i]->fullname)))
471 {
472 if(i)
473 {
474 PROFILE_FlushFile();
475 tempProfile=MRUProfile[i];
476 for(j=i;j>0;j--)
477 MRUProfile[j]=MRUProfile[j-1];
478 CurProfile=tempProfile;
479 }
480 if(!stat(CurProfile->fullname,&buf) && CurProfile->mtime==buf.st_mtime)
481 dprintf(("Kernel32:Profile:(%s): already opened (mru=%d)\n",
482 filename, i ));
483 else
484 dprintf(("Kernel32:Profile:(%s): already opened, needs refreshing (mru=%d)\n",
485 filename, i ));
486 return TRUE;
487 }
488 }
489
490 /* Rotate the oldest to the top to be replaced */
491
492 if(i==N_CACHED_PROFILES)
493 {
494 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
495 for(i=N_CACHED_PROFILES-1;i>0;i--)
496 MRUProfile[i]=MRUProfile[i-1];
497 CurProfile=tempProfile;
498 }
499
500 /* Flush the profile */
501
502 if(CurProfile->filename) PROFILE_ReleaseFile();
503
504 CurProfile->filename = HEAP_strdupA(SystemHeap,0,filename);
505
506 /* check for path */
507
508 if ((!strchr( filename,'/') &&
509 !strchr( filename,'\\')) ||
510 !strchr( filename,':'))
511 {
512 char fullname[MAX_PATHNAME_LEN];
513
514 GetWindowsDirectoryA(fullname,sizeof(fullname));
515 strcat(fullname,"\\");
516 strcat(fullname,filename);
517 CurProfile->fullname = HEAP_strdupA(SystemHeap,0,fullname);
518 } else CurProfile->fullname = HEAP_strdupA(SystemHeap,0,filename);
519
520 file = fopen(CurProfile->fullname,"r");
521 if (file)
522 {
523 dprintf(("Kernel32:Profile:(%s): found it in %s\n",
524 filename, CurProfile->fullname ));
525
526 CurProfile->section = PROFILE_Load( file );
527 fclose( file );
528 if(!stat(CurProfile->fullname,&buf))
529 CurProfile->mtime=buf.st_mtime;
530 }
531 else
532 {
533 /* Does not exist yet, we will create it in PROFILE_FlushFile */
534 dprintf(("Kernel32:Profile:profile file %s not found\n", CurProfile->fullname ));
535 }
536 return TRUE;
537}
538
539
540/***********************************************************************
541 * PROFILE_GetSection
542 *
543 * Returns all keys of a section.
544 * If return_values is TRUE, also include the corresponding values.
545 */
546static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
547 LPSTR buffer, UINT len, BOOL handle_env,
548 BOOL return_values )
549{
550 PROFILEKEY *key;
551 while (section)
552 {
553 if (section->name && !strcasecmp( section->name, section_name ))
554 {
555 UINT oldlen = len;
556 for (key = section->key; key; key = key->next)
557 {
558 if (len <= 2) break;
559 if (!*key->name) continue; /* Skip empty lines */
560 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
561 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
562 len -= strlen(buffer) + 1;
563 buffer += strlen(buffer) + 1;
564 if (return_values && key->value) {
565 buffer[-1] = '=';
566 PROFILE_CopyEntry ( buffer,
567 key->value, len - 1, handle_env );
568 len -= strlen(buffer) + 1;
569 buffer += strlen(buffer) + 1;
570 }
571 }
572 *buffer = '\0';
573 if (len <= 1)
574 /*If either lpszSection or lpszKey is NULL and the supplied
575 destination buffer is too small to hold all the strings,
576 the last string is truncated and followed by two null characters.
577 In this case, the return value is equal to cchReturnBuffer
578 minus two. */
579 {
580 buffer[-1] = '\0';
581 return oldlen - 2;
582 }
583 return oldlen - len;
584 }
585 section = section->next;
586 }
587 buffer[0] = buffer[1] = '\0';
588 return 0;
589}
590
591
592static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
593{
594 LPSTR buf = buffer;
595 WORD l, cursize = 0;
596 PROFILESECTION *section;
597
598 for (section = CurProfile->section; section; section = section->next)
599 if (section->name) {
600 l = strlen(section->name);
601 cursize += l+1;
602 if (cursize > len+1)
603 return len-2;
604
605 strcpy(buf, section->name);
606 buf += l+1;
607 }
608
609 *buf=0;
610 buf++;
611 return buf-buffer;
612}
613
614
615/***********************************************************************
616 * PROFILE_GetString
617 *
618 * Get a profile string.
619 */
620static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
621 LPCSTR def_val, LPSTR buffer, UINT len )
622{
623 PROFILEKEY *key = NULL;
624
625 if (!def_val) def_val = "";
626 if (key_name && key_name[0])
627 {
628 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
629 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
630 len, FALSE );
631 dprintf(("Kernel32:Profile:('%s','%s','%s'): returning '%s'\n",
632 section, key_name, def_val, buffer ));
633 return strlen( buffer );
634 }
635 if (section && section[0])
636 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
637 FALSE, FALSE);
638 /* undocumented; both section and key_name are NULL */
639 return PROFILE_GetSectionNames(buffer, len);
640}
641
642
643/***********************************************************************
644 * PROFILE_SetString
645 *
646 * Set a profile string.
647 */
648static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
649 LPCSTR value )
650{
651 if (!key_name) /* Delete a whole section */
652 {
653 dprintf(("Kernel32:Profile:('%s')\n", section_name));
654 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
655 section_name );
656 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
657 this is not an error on application's level.*/
658 }
659 else if (!value) /* Delete a key */
660 {
661 dprintf(("Kernel32:Profile:('%s','%s')\n",
662 section_name, key_name ));
663 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
664 section_name, key_name );
665 return TRUE; /* same error handling as above */
666 }
667 else /* Set the key value */
668 {
669 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
670 key_name, TRUE );
671 dprintf(("Kernel32:Profile:('%s','%s','%s'): \n",
672 section_name, key_name, value ));
673 if (!key) return FALSE;
674 if (key->value)
675 {
676 if (!strcmp( key->value, value ))
677 {
678 dprintf(("Kernel32:Profile: no change needed\n" ));
679 return TRUE; /* No change needed */
680 }
681 dprintf(("Kernel32:Profile: replacing '%s'\n", key->value ));
682 HeapFree( SystemHeap, 0, key->value );
683 }
684 else dprintf(("Kernel32:Profile: creating key\n" ));
685 key->value = HEAP_strdupA( SystemHeap, 0, value );
686 CurProfile->changed = TRUE;
687 }
688 return TRUE;
689}
690
691
692/***********************************************************************
693 * PROFILE_GetWineIniString
694 *
695 * Get a config string from the wine.ini file.
696 */
697int PROFILE_GetWineIniString( const char *section, const char *key_name,
698 const char *def, char *buffer, int len )
699{
700 int ret;
701
702 EnterCriticalSection( &PROFILE_CritSect );
703
704 if (key_name)
705 {
706 PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
707 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
708 len, TRUE );
709 dprintf(("Kernel32:Profile:('%s','%s','%s'): returning '%s'\n",
710 section, key_name, def, buffer ));
711 ret = strlen( buffer );
712 }
713 else
714 {
715 ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
716 }
717 LeaveCriticalSection( &PROFILE_CritSect );
718
719 return ret;
720}
721
722
723/***********************************************************************
724 * PROFILE_GetWineIniInt
725 *
726 * Get a config integer from the wine.ini file.
727 */
728int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
729{
730 char buffer[20];
731 char *p;
732 long result;
733 PROFILEKEY *key;
734 int ret;
735
736 EnterCriticalSection( &PROFILE_CritSect );
737
738 key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
739 if (!key || !key->value) {
740 ret = def;
741 } else {
742 PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
743 result = strtol( buffer, &p, 0 );
744 ret = (p == buffer) ? 0 /* No digits at all */ : (int)result;
745 }
746
747 LeaveCriticalSection( &PROFILE_CritSect );
748
749 return ret;
750}
751
752
753/******************************************************************************
754 *
755 * int PROFILE_EnumerateWineIniSection(
756 * char const *section, #Name of the section to enumerate
757 * void (*cbfn)(char const *key, char const *value, void *user),
758 * # Address of the callback function
759 * void *user ) # User-specified pointer.
760 *
761 * For each entry in a section in the wine.conf file, this function will
762 * call the specified callback function, informing it of each key and
763 * value. An optional user pointer may be passed to it (if this is not
764 * needed, pass NULL through it and ignore the value in the callback
765 * function).
766 *
767 * The callback function must accept three parameters:
768 * The name of the key (char const *)
769 * The value of the key (char const *)
770 * A user-specified parameter (void *)
771 * Note that the first two are char CONST *'s, not char *'s! The callback
772 * MUST not modify these strings!
773 *
774 * The return value indicates the number of times the callback function
775 * was called.
776 */
777int PROFILE_EnumerateWineIniSection(
778 char const *section,
779 void (*cbfn)(char const *, char const *, void *),
780 void *userptr )
781{
782 PROFILESECTION *scansect;
783 PROFILEKEY *scankey;
784 int calls = 0;
785
786 EnterCriticalSection( &PROFILE_CritSect );
787
788 /* Search for the correct section */
789 for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
790 if(scansect->name && !strcasecmp(scansect->name, section)) {
791
792 /* Enumerate each key with the callback */
793 for(scankey = scansect->key; scankey; scankey = scankey->next) {
794
795 /* Ignore blank entries -- these shouldn't exist, but let's
796 be extra careful */
797 if(scankey->name[0]) {
798 cbfn(scankey->name, scankey->value, userptr);
799 ++calls;
800 }
801 }
802
803 break;
804 }
805 }
806 LeaveCriticalSection( &PROFILE_CritSect );
807
808 return calls;
809}
810
811
812/******************************************************************************
813 *
814 * int PROFILE_GetWineIniBool(
815 * char const *section,
816 * char const *key_name,
817 * int def )
818 *
819 * Reads a boolean value from the wine.ini file. This function attempts to
820 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
821 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
822 * true. Anything else results in the return of the default value.
823 *
824 * This function uses 1 to indicate true, and 0 for false. You can check
825 * for existence by setting def to something other than 0 or 1 and
826 * examining the return value.
827 */
828int PROFILE_GetWineIniBool(
829 char const *section,
830 char const *key_name,
831 int def )
832{
833 char key_value[2];
834 int retval;
835
836 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
837
838 switch(key_value[0]) {
839 case 'n':
840 case 'N':
841 case 'f':
842 case 'F':
843 case '0':
844 retval = 0;
845 break;
846
847 case 'y':
848 case 'Y':
849 case 't':
850 case 'T':
851 case '1':
852 retval = 1;
853 break;
854
855 default:
856 retval = def;
857 }
858
859 dprintf(("Kernel32:Profile:(\"%s\", \"%s\", %s), "
860 "[%c], ret %s.\n", section, key_name,
861 def ? "TRUE" : "FALSE", key_value[0],
862 retval ? "TRUE" : "FALSE"));
863
864 return retval;
865}
866
867
868#if 0
869/***********************************************************************
870 * PROFILE_LoadWineIni
871 *
872 * Load the wine.ini file.
873 */
874int PROFILE_LoadWineIni(void)
875{
876 char buffer[MAX_PATHNAME_LEN];
877 const char *p;
878 FILE *f;
879
880 InitializeCriticalSection( &PROFILE_CritSect );
881 MakeCriticalSectionGlobal( &PROFILE_CritSect );
882
883 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
884 {
885 /* Open -config specified file */
886 PROFILE_WineProfile = PROFILE_Load ( f);
887 fclose ( f );
888 strncpy(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN-1);
889 return 1;
890 }
891
892 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
893 {
894 PROFILE_WineProfile = PROFILE_Load( f );
895 fclose( f );
896 strncpy(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN-1);
897 return 1;
898 }
899 if ((p = getenv( "HOME" )) != NULL)
900 {
901 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
902 strcat( buffer, PROFILE_WineIniName );
903 if ((f = fopen( buffer, "r" )) != NULL)
904 {
905 PROFILE_WineProfile = PROFILE_Load( f );
906 fclose( f );
907 strncpy(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN-1);
908 return 1;
909 }
910 }
911 else dprintf(("Kernel32:Profile:could not get $HOME value for config file.\n" ));
912
913 /* Try global file */
914
915 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
916 {
917 PROFILE_WineProfile = PROFILE_Load( f );
918 fclose( f );
919 strncpy(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN-1);
920 return 1;
921 }
922 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
923 WINE_INI_GLOBAL, PROFILE_WineIniName );
924 return 0;
925}
926
927
928/***********************************************************************
929 * PROFILE_UsageWineIni
930 *
931 * Explain the wine.ini file to those who don't read documentation.
932 * Keep below one screenful in length so that error messages above are
933 * noticed.
934 */
935void PROFILE_UsageWineIni(void)
936{
937 MESSAGE("Perhaps you have not properly edited or created "
938 "your Wine configuration file.\n");
939 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
940 MESSAGE(" or it is determined by the -config option or from\n"
941 " the WINE_INI environment variable.\n");
942 if (*PROFILE_WineIniUsed)
943 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
944 /* RTFM, so to say */
945}
946#endif
947
948/***********************************************************************
949 * PROFILE_GetStringItem
950 *
951 * Convenience function that turns a string 'xxx, yyy, zzz' into
952 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
953 */
954char* PROFILE_GetStringItem( char* start )
955{
956 char* lpchX, *lpch;
957
958 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
959 {
960 if( *lpchX == ',' )
961 {
962 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
963 while( *(++lpchX) )
964 if( !PROFILE_isspace(*lpchX) ) return lpchX;
965 }
966 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
967 else lpch = NULL;
968 }
969 if( lpch ) *lpch = '\0';
970 return NULL;
971}
972
973/********************* API functions **********************************/
974
975/***********************************************************************
976 * GetProfileInt32A (KERNEL32.264)
977 */
978UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
979{
980 return GetPrivateProfileIntA( section, entry, def_val, WINININAME );
981}
982
983/***********************************************************************
984 * GetProfileInt32W (KERNEL32.264)
985 */
986UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
987{
988 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
989 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
990}
991
992/***********************************************************************
993 * GetProfileString32A (KERNEL32.268)
994 */
995INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
996 LPSTR buffer, UINT len )
997{
998 return GetPrivateProfileStringA( section, entry, def_val,
999 buffer, len, WINININAME );
1000}
1001
1002/***********************************************************************
1003 * GetProfileString32W (KERNEL32.269)
1004 */
1005INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1006 LPCWSTR def_val, LPWSTR buffer, UINT len )
1007{
1008 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
1009 return GetPrivateProfileStringW( section, entry, def_val,
1010 buffer, len, wininiW );
1011}
1012
1013/***********************************************************************
1014 * WriteProfileString32A (KERNEL32.587)
1015 */
1016BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1017 LPCSTR string )
1018{
1019 return WritePrivateProfileStringA( section, entry, string, WINININAME );
1020}
1021
1022/***********************************************************************
1023 * WriteProfileString32W (KERNEL32.588)
1024 */
1025BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1026 LPCWSTR string )
1027{
1028 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
1029 return WritePrivateProfileStringW( section, entry, string, wininiW );
1030}
1031
1032/***********************************************************************
1033 * GetPrivateProfileInt32A (KERNEL32.251)
1034 */
1035UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1036 INT def_val, LPCSTR filename )
1037{
1038 char buffer[20];
1039 char *p;
1040 long result;
1041
1042 GetPrivateProfileStringA( section, entry, "",
1043 buffer, sizeof(buffer), filename );
1044 if (!buffer[0]) return (UINT)def_val;
1045 result = strtol( buffer, &p, 0 );
1046 if (p == buffer) return 0; /* No digits at all */
1047 return (UINT)result;
1048}
1049
1050/***********************************************************************
1051 * GetPrivateProfileInt32W (KERNEL32.252)
1052 */
1053UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1054 INT def_val, LPCWSTR filename )
1055{
1056 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1057 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1058 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1059 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1060 HeapFree( GetProcessHeap(), 0, sectionA );
1061 HeapFree( GetProcessHeap(), 0, filenameA );
1062 HeapFree( GetProcessHeap(), 0, entryA );
1063 return res;
1064}
1065
1066/***********************************************************************
1067 * GetPrivateProfileString32A (KERNEL32.255)
1068 */
1069INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1070 LPCSTR def_val, LPSTR buffer,
1071 UINT len, LPCSTR filename )
1072{
1073 int ret;
1074
1075 if (!filename)
1076 filename = WINININAME;
1077
1078 EnterCriticalSection( &PROFILE_CritSect );
1079
1080 if (PROFILE_Open( filename )) {
1081 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1082 } else {
1083 lstrcpynA( buffer, def_val, len );
1084 ret = strlen( buffer );
1085 }
1086
1087 LeaveCriticalSection( &PROFILE_CritSect );
1088
1089 return ret;
1090}
1091
1092/***********************************************************************
1093 * GetPrivateProfileString32W (KERNEL32.256)
1094 */
1095INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1096 LPCWSTR def_val, LPWSTR buffer,
1097 UINT len, LPCWSTR filename )
1098{
1099 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1100 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1101 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1102 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1103 LPSTR bufferA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
1104 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1105 bufferA, len, filenameA );
1106 lstrcpynAtoW( buffer, bufferA, len );
1107 HeapFree( GetProcessHeap(), 0, sectionA );
1108 HeapFree( GetProcessHeap(), 0, entryA );
1109 HeapFree( GetProcessHeap(), 0, filenameA );
1110 HeapFree( GetProcessHeap(), 0, def_valA );
1111 HeapFree( GetProcessHeap(), 0, bufferA);
1112 return ret;
1113}
1114
1115/***********************************************************************
1116 * GetPrivateProfileSection32A (KERNEL32.255)
1117 */
1118INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1119 DWORD len, LPCSTR filename )
1120{
1121 int ret = 0;
1122
1123 EnterCriticalSection( &PROFILE_CritSect );
1124
1125 if (PROFILE_Open( filename ))
1126 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1127 FALSE, TRUE);
1128
1129 LeaveCriticalSection( &PROFILE_CritSect );
1130
1131 return ret;
1132}
1133
1134/***********************************************************************
1135 * GetPrivateProfileSection32W (KERNEL32.256)
1136 */
1137
1138INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1139 DWORD len, LPCWSTR filename )
1140
1141{
1142 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1143 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1144 LPSTR bufferA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
1145 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1146 filenameA );
1147 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1148 HeapFree( GetProcessHeap(), 0, sectionA );
1149 HeapFree( GetProcessHeap(), 0, filenameA );
1150 HeapFree( GetProcessHeap(), 0, bufferA);
1151 return ret;
1152}
1153
1154/***********************************************************************
1155 * GetProfileSection32A (KERNEL32.268)
1156 */
1157INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1158{
1159 return GetPrivateProfileSectionA( section, buffer, len, WINININAME );
1160}
1161
1162/***********************************************************************
1163 * GetProfileSection32W (KERNEL32)
1164 */
1165INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1166{
1167 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
1168 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1169}
1170
1171/***********************************************************************
1172 * WritePrivateProfileString32A (KERNEL32.582)
1173 */
1174BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1175 LPCSTR string, LPCSTR filename )
1176{
1177 BOOL ret = FALSE;
1178
1179 EnterCriticalSection( &PROFILE_CritSect );
1180
1181 if (PROFILE_Open( filename ))
1182 {
1183 if (!section && !entry && !string)
1184 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1185 else
1186 ret = PROFILE_SetString( section, entry, string );
1187 }
1188
1189 LeaveCriticalSection( &PROFILE_CritSect );
1190 return ret;
1191}
1192
1193/***********************************************************************
1194 * WritePrivateProfileString32W (KERNEL32.583)
1195 */
1196BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1197 LPCWSTR string, LPCWSTR filename )
1198{
1199 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1200 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1201 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1202 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1203 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1204 stringA, filenameA );
1205 HeapFree( GetProcessHeap(), 0, sectionA );
1206 HeapFree( GetProcessHeap(), 0, entryA );
1207 HeapFree( GetProcessHeap(), 0, stringA );
1208 HeapFree( GetProcessHeap(), 0, filenameA );
1209 return res;
1210}
1211
1212/***********************************************************************
1213 * WritePrivateProfileSection32A (KERNEL32)
1214 */
1215BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1216 LPCSTR string, LPCSTR filename )
1217{
1218 char *p =(char*)string;
1219
1220 dprintf(("Kernel32:Profile:fixme WritePrivateProfileSection32A empty stub\n"));
1221 return FALSE;
1222}
1223
1224/***********************************************************************
1225 * WritePrivateProfileSection32W (KERNEL32)
1226 */
1227BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1228 LPCWSTR string, LPCWSTR filename)
1229
1230{
1231 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1232 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1233 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1234 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1235 HeapFree( GetProcessHeap(), 0, sectionA );
1236 HeapFree( GetProcessHeap(), 0, stringA );
1237 HeapFree( GetProcessHeap(), 0, filenameA );
1238 return res;
1239}
1240
1241/***********************************************************************
1242 * WriteProfileSection32A (KERNEL32.747)
1243 */
1244BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1245
1246{
1247 return WritePrivateProfileSectionA( section, keys_n_values, WINININAME);
1248}
1249
1250/***********************************************************************
1251 * WriteProfileSection32W (KERNEL32.748)
1252 */
1253BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1254{
1255 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME);
1256
1257 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1258}
1259
1260/***********************************************************************
1261 * GetPrivateProfileSectionNames16 (KERNEL.143)
1262 */
1263WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1264 LPCSTR filename )
1265{
1266 WORD ret = 0;
1267
1268 EnterCriticalSection( &PROFILE_CritSect );
1269
1270 if (PROFILE_Open( filename ))
1271 ret = PROFILE_GetSectionNames(buffer, size);
1272
1273 LeaveCriticalSection( &PROFILE_CritSect );
1274
1275 return ret;
1276}
1277
1278/***********************************************************************
1279 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1280 */
1281DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1282 LPCSTR filename)
1283
1284{
1285 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1286}
1287
1288/***********************************************************************
1289 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1290 */
1291DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1292 LPCWSTR filename)
1293
1294{
1295 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1296 LPSTR bufferA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, size);
1297
1298 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1299 lstrcpynAtoW( buffer, bufferA, size);
1300 HeapFree( GetProcessHeap(), 0, bufferA);
1301 HeapFree( GetProcessHeap(), 0, filenameA );
1302
1303 return ret;
1304}
1305
1306/***********************************************************************
1307 * GetPrivateProfileStruct32A (KERNEL32.370)
1308 */
1309BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1310 LPVOID buf, UINT len, LPCSTR filename)
1311{
1312 BOOL ret = FALSE;
1313
1314 EnterCriticalSection( &PROFILE_CritSect );
1315
1316 if (PROFILE_Open( filename )) {
1317 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1318 if (k) {
1319 lstrcpynA( (LPSTR)buf, k->value, strlen(k->value));
1320 ret = TRUE;
1321 }
1322 }
1323 LeaveCriticalSection( &PROFILE_CritSect );
1324
1325 return FALSE;
1326}
1327
1328/***********************************************************************
1329 * GetPrivateProfileStruct32W (KERNEL32.543)
1330 */
1331BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1332 LPVOID buffer, UINT len, LPCWSTR filename)
1333{
1334 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1335 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1336 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1337 LPSTR bufferA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
1338
1339 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1340 len, filenameA );
1341 lstrcpynAtoW( (LPWSTR)buffer, bufferA, len );
1342 HeapFree( GetProcessHeap(), 0, bufferA);
1343 HeapFree( GetProcessHeap(), 0, sectionA );
1344 HeapFree( GetProcessHeap(), 0, keyA );
1345 HeapFree( GetProcessHeap(), 0, filenameA );
1346
1347 return ret;
1348}
1349
1350
1351/***********************************************************************
1352 * WritePrivateProfileStruct32A (KERNEL32.744)
1353 */
1354BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1355 LPVOID buf, UINT bufsize, LPCSTR filename)
1356{
1357 BOOL ret = FALSE;
1358
1359 if (!section && !key && !buf) /* flush the cache */
1360 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1361
1362 EnterCriticalSection( &PROFILE_CritSect );
1363
1364 if (PROFILE_Open( filename ))
1365 ret = PROFILE_SetString( section, key, (LPCSTR)buf );
1366
1367 LeaveCriticalSection( &PROFILE_CritSect );
1368
1369 return ret;
1370}
1371
1372/***********************************************************************
1373 * WritePrivateProfileStruct32W (KERNEL32.544)
1374 */
1375BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1376 LPVOID buf, UINT bufsize, LPCWSTR filename)
1377{
1378 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1379 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1380 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1381 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1382 filenameA );
1383 HeapFree( GetProcessHeap(), 0, sectionA );
1384 HeapFree( GetProcessHeap(), 0, keyA );
1385 HeapFree( GetProcessHeap(), 0, filenameA );
1386
1387 return ret;
1388}
1389
1390/***********************************************************************
1391 * WriteOutProfiles (KERNEL.315)
1392 * CB: original: 16 bit function
1393 * here: necessary to save open ini files
1394 */
1395void WINAPI WriteOutProfiles(void)
1396{
1397 PROFILE *lastCurProfile;
1398 INT x;
1399
1400 EnterCriticalSection(&PROFILE_CritSect);
1401
1402 if (CurProfile && CurProfile->filename)
1403 PROFILE_FlushFile(); //flash current
1404
1405 if (MRUProfile)
1406 {
1407 lastCurProfile = CurProfile;
1408 for(x = 1;x < N_CACHED_PROFILES;x++)
1409 {
1410 if (MRUProfile[x] && MRUProfile[x]->filename)
1411 {
1412 CurProfile = MRUProfile[x];
1413 PROFILE_FlushFile();
1414 }
1415 }
1416 CurProfile = lastCurProfile;
1417 }
1418 LeaveCriticalSection(&PROFILE_CritSect);
1419}
1420
1421
Note: See TracBrowser for help on using the repository browser.