1 /* $Id: profile.c,v 1.12 2004/06/13 20:04:56 navaraf Exp $
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
7 * PROJECT: ReactOS system libraries
8 * FILE: lib/kernel32/misc/profile.c
9 * PURPOSE: Profiles functions
10 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
11 * modified from WINE [ Onno Hovers, (onno@stack.urc.tue.nl) ]
21 static CRITICAL_SECTION ProfileLock
;
23 typedef struct tagPROFILEKEY
26 struct tagPROFILEKEY
*Next
;
30 typedef struct tagPROFILESECTION
32 struct tagPROFILEKEY
*Key
;
33 struct tagPROFILESECTION
*Next
;
41 PROFILESECTION
*Section
;
43 FILETIME LastWriteTime
;
47 #define N_CACHED_PROFILES 10
49 /* Cached profile files */
50 static PROFILE
*MRUProfile
[N_CACHED_PROFILES
]={NULL
};
52 #define CurProfile (MRUProfile[0])
54 #define PROFILE_MAX_LINE_LEN 1024
56 /* Check for comments in profile */
57 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
59 /* FUNCTIONS *****************************************************************/
61 /***********************************************************************
64 * Copy the content of an entry into a buffer, removing quotes, and possibly
65 * translating environment variables.
68 PROFILE_CopyEntry(LPWSTR Buffer
, LPCWSTR Value
, int Len
, BOOL StripQuote
)
77 if (StripQuote
&& (L
'\'' == *Value
|| L
'\"' == *Value
))
79 if (L
'\0' != Value
[1] && (Value
[wcslen(Value
) - 1] == *Value
))
85 lstrcpynW(Buffer
, Value
, Len
);
86 if (L
'\0' != Quote
&& wcslen(Value
) <= Len
)
88 Buffer
[wcslen(Buffer
) - 1] = L
'\0';
93 /***********************************************************************
96 * Save a profile tree to a file.
99 PROFILE_Save(HANDLE File
, PROFILESECTION
*Section
)
102 char Buffer
[PROFILE_MAX_LINE_LEN
];
105 for ( ; NULL
!= Section
; Section
= Section
->Next
)
107 if (L
'\0' != Section
->Name
[0])
109 strcpy(Buffer
, "\r\n[");
110 WideCharToMultiByte(CP_ACP
, 0, Section
->Name
, -1, Buffer
+ 3, sizeof(Buffer
) - 6, NULL
, NULL
);
111 strcat(Buffer
, "]\r\n");
112 WriteFile(File
, Buffer
, strlen(Buffer
), &BytesWritten
, NULL
);
114 for (Key
= Section
->Key
; NULL
!= Key
; Key
= Key
->Next
)
116 WideCharToMultiByte(CP_ACP
, 0, Key
->Name
, -1, Buffer
, sizeof(Buffer
) - 3, NULL
, NULL
);
120 WideCharToMultiByte(CP_ACP
, 0, Key
->Value
, -1, Buffer
+ strlen(Buffer
),
121 sizeof(Buffer
) - strlen(Buffer
) - 2, NULL
, NULL
);
123 strcat(Buffer
, "\r\n");
124 WriteFile(File
, Buffer
, strlen(Buffer
), &BytesWritten
, NULL
);
130 /***********************************************************************
133 * Free a profile tree.
136 PROFILE_Free(PROFILESECTION
*Section
)
138 PROFILESECTION
*NextSection
;
139 PROFILEKEY
*Key
, *NextKey
;
141 for ( ; NULL
!= Section
; Section
= NextSection
)
143 for (Key
= Section
->Key
; NULL
!= Key
; Key
= NextKey
)
146 if (NULL
!= Key
->Value
)
148 HeapFree(GetProcessHeap(), 0, Key
->Value
);
150 HeapFree(GetProcessHeap(), 0, Key
);
152 NextSection
= Section
->Next
;
153 HeapFree(GetProcessHeap(), 0, Section
);
158 PROFILE_isspace(char c
)
164 if ('\r' == c
|| 0x1a == c
)
166 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
173 /***********************************************************************
176 * Load a profile tree from a file.
178 static PROFILESECTION
* FASTCALL
179 PROFILE_Load(HANDLE File
)
183 PROFILESECTION
*Section
, *FirstSection
;
184 PROFILESECTION
**NextSection
;
185 PROFILEKEY
*Key
, *PrevKey
, **NextKey
;
186 LARGE_INTEGER FileSize
;
191 FileSize
.u
.LowPart
= GetFileSize(File
, &FileSize
.u
.HighPart
);
192 if (INVALID_FILE_SIZE
== FileSize
.u
.LowPart
&& 0 != GetLastError())
197 FirstSection
= HeapAlloc(GetProcessHeap(), 0, sizeof(*Section
));
198 if (NULL
== FirstSection
)
202 FirstSection
->Name
[0] = L
'\0';
203 FirstSection
->Key
= NULL
;
204 FirstSection
->Next
= NULL
;
205 NextSection
= &FirstSection
->Next
;
206 NextKey
= &FirstSection
->Key
;
209 if (0 == FileSize
.QuadPart
)
213 Mapping
= CreateFileMappingW(File
, NULL
, PAGE_READONLY
| SEC_COMMIT
, 0, 0, NULL
);
216 HeapFree(GetProcessHeap(), 0, FirstSection
);
219 BaseAddress
= MapViewOfFile(Mapping
, FILE_MAP_READ
, 0, 0, 0);
220 if (NULL
== BaseAddress
)
222 CloseHandle(Mapping
);
223 HeapFree(GetProcessHeap(), 0, FirstSection
);
227 Input
= (char *) BaseAddress
;
228 End
= Input
+ FileSize
.QuadPart
;
231 while (Input
< End
&& PROFILE_isspace(*Input
))
239 if ('[' == *Input
) /* section start */
242 while (p
< End
&& ']' != *p
&& '\n' != *p
)
246 if (p
< End
&& ']' == *p
)
249 if (NULL
== (Section
= HeapAlloc(GetProcessHeap(), 0,
250 sizeof(*Section
) + Len
* sizeof(WCHAR
))))
254 MultiByteToWideChar(CP_ACP
, 0, Input
, Len
, Section
->Name
, Len
);
255 Section
->Name
[Len
] = L
'\0';
257 Section
->Next
= NULL
;
258 *NextSection
= Section
;
259 NextSection
= &Section
->Next
;
260 NextKey
= &Section
->Key
;
263 DPRINT("New section: %S\n", Section
->Name
);
267 while (Input
< End
&& '\n' != *Input
)
271 Input
++; /* Skip past the \n */
277 while (p
< End
&& '=' != *p
&& '\n' != *p
)
279 if (! PROFILE_isspace(*p
))
286 if (p
< End
&& '=' == *p
)
288 Len
= p2
- Input
+ 1;
289 if (NULL
== (Key
= HeapAlloc(GetProcessHeap(), 0,
290 sizeof(*Key
) + Len
* sizeof(WCHAR
))))
294 MultiByteToWideChar(CP_ACP
, 0, Input
, Len
, Key
->Name
, Len
);
295 Key
->Name
[Len
] = L
'\0';
297 while (Input
< End
&& '\n' != *Input
&& PROFILE_isspace(*Input
))
301 if (End
<= Input
|| '\n' == *Input
)
309 while (p
< End
&& '\n' != *p
)
311 if (! PROFILE_isspace(*p
))
317 Len
= p2
- Input
+ 1;
318 if (NULL
== (Key
->Value
= HeapAlloc(GetProcessHeap(), 0,
319 (Len
+ 1) * sizeof(WCHAR
))))
323 MultiByteToWideChar(CP_ACP
, 0, Input
, Len
, Key
->Value
, Len
);
324 Key
->Value
[Len
] = L
'\0';
328 NextKey
= &Key
->Next
;
331 DPRINT("New key: name=%S, value=%S\n",
332 Key
->Name
, NULL
!= Key
->Value
? Key
->Value
: L
"(none)");
337 while (Input
< End
&& '\n' != *Input
)
341 Input
++; /* Skip past the \n */
344 UnmapViewOfFile(BaseAddress
);
345 CloseHandle(Mapping
);
351 /***********************************************************************
354 * Find a key in a profile tree, optionally creating it.
356 static PROFILEKEY
* FASTCALL
357 PROFILE_Find(PROFILESECTION
**Section
, LPCWSTR SectionName
,
358 LPCWSTR KeyName
, BOOL Create
, BOOL CreateAlways
)
363 while (PROFILE_isspace(*SectionName
))
367 p
= SectionName
+ wcslen(SectionName
) - 1;
368 while (SectionName
< p
&& PROFILE_isspace(*p
))
372 SecLen
= p
- SectionName
+ 1;
374 while (PROFILE_isspace(*KeyName
))
378 p
= KeyName
+ wcslen(KeyName
) - 1;
379 while (KeyName
< p
&& PROFILE_isspace(*p
))
383 KeyLen
= p
- KeyName
+ 1;
385 while (NULL
!= *Section
)
387 if (L
'\0' != ((*Section
)->Name
[0])
388 && 0 == _wcsnicmp((*Section
)->Name
, SectionName
, SecLen
)
389 && L
'\0' == ((*Section
)->Name
)[SecLen
])
391 PROFILEKEY
**Key
= &(*Section
)->Key
;
395 /* If create_always is FALSE then we check if the keyname
396 * already exists. Otherwise we add it regardless of its
397 * existence, to allow keys to be added more than once in
402 if (0 == _wcsnicmp((*Key
)->Name
, KeyName
, KeyLen
)
403 && L
'\0' == ((*Key
)->Name
)[KeyLen
])
414 if (NULL
== (*Key
= HeapAlloc(GetProcessHeap(), 0,
415 sizeof(PROFILEKEY
) + wcslen(KeyName
) * sizeof(WCHAR
))))
419 wcscpy((*Key
)->Name
, KeyName
);
420 (*Key
)->Value
= NULL
;
424 Section
= &(*Section
)->Next
;
432 *Section
= HeapAlloc(GetProcessHeap(), 0,
433 sizeof(PROFILESECTION
) + wcslen(SectionName
) * sizeof(WCHAR
));
434 if (NULL
== *Section
)
438 wcscpy((*Section
)->Name
, SectionName
);
439 (*Section
)->Next
= NULL
;
440 if (NULL
== ((*Section
)->Key
= HeapAlloc(GetProcessHeap(), 0,
441 sizeof(PROFILEKEY
) + wcslen(KeyName
) * sizeof(WCHAR
))))
443 HeapFree(GetProcessHeap(), 0, *Section
);
446 wcscpy((*Section
)->Key
->Name
, KeyName
);
447 (*Section
)->Key
->Value
= NULL
;
448 (*Section
)->Key
->Next
= NULL
;
450 return (*Section
)->Key
;
454 /***********************************************************************
457 * Flush the current profile to disk if changed.
460 PROFILE_FlushFile(void)
462 HANDLE File
= INVALID_HANDLE_VALUE
;
463 FILETIME LastWriteTime
;
465 if (NULL
== CurProfile
)
467 DPRINT("No current profile!\n");
471 if (! CurProfile
->Changed
|| NULL
== CurProfile
->FullName
)
476 File
= CreateFileW(CurProfile
->FullName
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
477 if (INVALID_HANDLE_VALUE
== File
)
479 DPRINT1("could not save profile file %s\n", CurProfile
->FullName
);
483 DPRINT("Saving %S\n", CurProfile
->FullName
);
484 PROFILE_Save(File
, CurProfile
->Section
);
485 if (GetFileTime(File
, NULL
, NULL
, &LastWriteTime
))
487 CurProfile
->LastWriteTime
.dwLowDateTime
= LastWriteTime
.dwLowDateTime
;
488 CurProfile
->LastWriteTime
.dwHighDateTime
= LastWriteTime
.dwHighDateTime
;
490 CurProfile
->Changed
= FALSE
;
497 /***********************************************************************
498 * PROFILE_ReleaseFile
500 * Flush the current profile to disk and remove it from the cache.
503 PROFILE_ReleaseFile(void)
506 PROFILE_Free(CurProfile
->Section
);
507 if (NULL
!= CurProfile
->FullName
)
509 HeapFree(GetProcessHeap(), 0, CurProfile
->FullName
);
511 CurProfile
->Changed
= FALSE
;
512 CurProfile
->Section
= NULL
;
513 CurProfile
->FullName
= NULL
;
514 CurProfile
->LastWriteTime
.dwLowDateTime
= 0;
515 CurProfile
->LastWriteTime
.dwHighDateTime
= 0;
519 /***********************************************************************
522 * Open a profile file, checking the cached file first.
525 PROFILE_Open(LPCWSTR FileName
)
527 WCHAR FullName
[MAX_PATH
];
528 HANDLE File
= INVALID_HANDLE_VALUE
;
530 PROFILE
*TempProfile
;
532 FILETIME LastWriteTime
;
534 /* Build full path name */
536 if (wcschr(FileName
, L
'/') || wcschr(FileName
, L
'\\') ||
537 wcschr(FileName
, L
':'))
539 FullLen
= GetFullPathNameW(FileName
, MAX_PATH
, FullName
, NULL
);
540 if (0 == FullLen
|| MAX_PATH
< FullLen
)
547 FullLen
= GetWindowsDirectoryW(FullName
, MAX_PATH
);
548 if (0 == FullLen
|| MAX_PATH
< FullLen
+ 1 + wcslen(FileName
))
552 wcscat(FullName
, L
"\\");
553 wcscat(FullName
, FileName
);
555 #if 0 /* FIXME: Not yet implemented */
556 FullLen
= GetLongPathNameW(FullName
, FullName
, MAX_PATH
);
557 if (0 == FullLen
|| MAX_PATH
< FullLen
)
563 /* Check for a match */
565 for (i
= 0; i
< N_CACHED_PROFILES
; i
++)
567 if (NULL
!= MRUProfile
[i
]->FullName
&& 0 == wcscmp(FullName
, MRUProfile
[i
]->FullName
))
572 TempProfile
= MRUProfile
[i
];
573 for(j
= i
; j
> 0; j
--)
575 MRUProfile
[j
] = MRUProfile
[j
- 1];
577 CurProfile
= TempProfile
;
579 File
= CreateFileW(FullName
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
580 NULL
, OPEN_EXISTING
, 0, NULL
);
581 if (INVALID_HANDLE_VALUE
== File
)
585 if (GetFileTime(File
, NULL
, NULL
, &LastWriteTime
) &&
586 LastWriteTime
.dwLowDateTime
== CurProfile
->LastWriteTime
.dwLowDateTime
&&
587 LastWriteTime
.dwHighDateTime
== CurProfile
->LastWriteTime
.dwHighDateTime
)
589 DPRINT("(%S): already opened (mru = %d)\n", FileName
, i
);
593 DPRINT("(%S): already opened, needs refreshing (mru = %d)\n", FileName
, i
);
601 /* Flush the old current profile */
604 /* Make the oldest profile the current one only in order to get rid of it */
605 if (N_CACHED_PROFILES
== i
)
607 TempProfile
= MRUProfile
[N_CACHED_PROFILES
- 1];
608 for(i
= N_CACHED_PROFILES
- 1; i
> 0; i
--)
610 MRUProfile
[i
] = MRUProfile
[i
- 1];
612 CurProfile
= TempProfile
;
614 if (NULL
!= CurProfile
->FullName
)
616 PROFILE_ReleaseFile();
619 /* OK, now that CurProfile is definitely free we assign it our new file */
620 CurProfile
->FullName
= HeapAlloc(GetProcessHeap(), 0, (wcslen(FullName
) + 1) * sizeof(WCHAR
));
621 if (NULL
!= CurProfile
->FullName
)
623 wcscpy(CurProfile
->FullName
, FullName
);
626 /* Try to open the profile file */
627 File
= CreateFileW(FullName
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
628 if (INVALID_HANDLE_VALUE
!= File
)
630 CurProfile
->Section
= PROFILE_Load(File
);
631 if (GetFileTime(File
, NULL
, NULL
, &LastWriteTime
))
633 CurProfile
->LastWriteTime
.dwLowDateTime
= LastWriteTime
.dwLowDateTime
;
634 CurProfile
->LastWriteTime
.dwHighDateTime
= LastWriteTime
.dwHighDateTime
;
640 /* Does not exist yet, we will create it in PROFILE_FlushFile */
641 DPRINT("profile file %S not found\n", FileName
);
648 /***********************************************************************
651 * Returns all keys of a section.
652 * If ReturnValues is TRUE, also include the corresponding values.
655 PROFILE_GetSection(PROFILESECTION
*Section
, LPCWSTR SectionName
,
656 LPWSTR Buffer
, UINT Len
, BOOL ReturnValues
)
665 DPRINT("%S,%p,%u\n", SectionName
, Buffer
, Len
);
667 while (NULL
!= Section
)
669 if (L
'\0' != Section
->Name
[0] && 0 == _wcsicmp(Section
->Name
, SectionName
))
672 for (Key
= Section
->Key
; NULL
!= Key
; Key
= Key
->Next
)
678 if (L
'\0' == *Key
->Name
)
680 continue; /* Skip empty lines */
682 if (IS_ENTRY_COMMENT(Key
->Name
))
684 continue; /* Skip comments */
686 PROFILE_CopyEntry(Buffer
, Key
->Name
, Len
- 1, FALSE
);
687 Len
-= wcslen(Buffer
) + 1;
688 Buffer
+= wcslen(Buffer
) + 1;
693 if (ReturnValues
&& NULL
!= Key
->Value
)
696 PROFILE_CopyEntry(Buffer
, Key
->Value
, Len
- 1, 0);
697 Len
-= wcslen(Buffer
) + 1;
698 Buffer
+= wcslen(Buffer
) + 1;
703 /*If either lpszSection or lpszKey is NULL and the supplied
704 destination buffer is too small to hold all the strings,
705 the last string is truncated and followed by two null characters.
706 In this case, the return value is equal to cchReturnBuffer
714 Section
= Section
->Next
;
717 Buffer
[0] = Buffer
[1] = L
'\0';
722 /* See GetPrivateProfileSectionNamesW for documentation */
724 PROFILE_GetSectionNames(LPWSTR Buffer
, UINT Len
)
728 PROFILESECTION
*Section
;
730 if (NULL
== Buffer
|| 0 == Len
)
743 Section
= CurProfile
->Section
;
744 while (NULL
!= Section
)
746 if (L
'\0' != Section
->Name
[0])
748 l
= wcslen(Section
->Name
) + 1;
753 wcsncpy(Buf
, Section
->Name
, f
- 1);
760 wcscpy(Buf
, Section
->Name
);
764 Section
= Section
->Next
;
772 /***********************************************************************
775 * Get a profile string.
778 PROFILE_GetString(LPCWSTR Section
, LPCWSTR KeyName
,
779 LPCWSTR DefVal
, LPWSTR Buffer
, UINT Len
)
781 PROFILEKEY
*Key
= NULL
;
795 if (L
'\0' == KeyName
[0])
799 Key
= PROFILE_Find(&CurProfile
->Section
, Section
, KeyName
, FALSE
, FALSE
);
800 PROFILE_CopyEntry(Buffer
, (NULL
!= Key
&& NULL
!= Key
->Value
) ? Key
->Value
: DefVal
,
802 DPRINT("(%S,%S,%S): returning %S\n", Section
, KeyName
, DefVal
, Buffer
);
803 return wcslen(Buffer
);
806 if (NULL
!= Section
&& L
'\0' != Section
[0])
808 INT Ret
= PROFILE_GetSection(CurProfile
->Section
, Section
, Buffer
, Len
, FALSE
);
809 if (L
'\0' == Buffer
[0]) /* no luck -> def_val */
811 PROFILE_CopyEntry(Buffer
, DefVal
, Len
, TRUE
);
812 Ret
= wcslen(Buffer
);
823 /***********************************************************************
824 * PROFILE_DeleteSection
826 * Delete a section from a profile tree.
829 PROFILE_DeleteSection(PROFILESECTION
**Section
, LPCWSTR Name
)
831 while (NULL
!= *Section
)
833 if (L
'\0' != (*Section
)->Name
[0] && 0 == _wcsicmp((*Section
)->Name
, Name
))
835 PROFILESECTION
*ToDel
= *Section
;
836 *Section
= ToDel
->Next
;
841 Section
= &(*Section
)->Next
;
848 /***********************************************************************
851 * Delete a key from a profile tree.
854 PROFILE_DeleteKey(PROFILESECTION
**Section
,
855 LPCWSTR SectionName
, LPCWSTR KeyName
)
859 if (L
'\0' != (*Section
)->Name
[0] && 0 == _wcsicmp((*Section
)->Name
, SectionName
))
861 PROFILEKEY
**Key
= &(*Section
)->Key
;
864 if (0 == _wcsicmp((*Key
)->Name
, KeyName
))
866 PROFILEKEY
*ToDel
= *Key
;
868 if (NULL
!= ToDel
->Value
)
870 HeapFree(GetProcessHeap(), 0, ToDel
->Value
);
872 HeapFree(GetProcessHeap(), 0, ToDel
);
878 Section
= &(*Section
)->Next
;
885 /***********************************************************************
888 * Set a profile string.
891 PROFILE_SetString(LPCWSTR SectionName
, LPCWSTR KeyName
,
892 LPCWSTR Value
, BOOL CreateAlways
)
896 if (NULL
== KeyName
) /* Delete a whole section */
898 DPRINT("(%S)\n", SectionName
);
899 CurProfile
->Changed
|= PROFILE_DeleteSection(&CurProfile
->Section
,
901 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
902 this is not an error on application's level.*/
905 if (NULL
== Value
) /* Delete a key */
907 DPRINT("(%S,%S)\n", SectionName
, KeyName
);
908 CurProfile
->Changed
|= PROFILE_DeleteKey(&CurProfile
->Section
,
909 SectionName
, KeyName
);
910 return TRUE
; /* same error handling as above */
913 /* Set the key value */
914 Key
= PROFILE_Find(&CurProfile
->Section
, SectionName
,
915 KeyName
, TRUE
, CreateAlways
);
916 DPRINT("(%S,%S,%S):\n", SectionName
, KeyName
, Value
);
921 if (NULL
!= Key
->Value
)
923 /* strip the leading spaces. We can safely strip \n\r and
924 * friends too, they should not happen here anyway. */
925 while (PROFILE_isspace(*Value
))
930 if (0 == wcscmp(Key
->Value
, Value
))
932 DPRINT(" no change needed\n");
933 return TRUE
; /* No change needed */
935 DPRINT(" replacing %S\n", Key
->Value
);
936 HeapFree(GetProcessHeap(), 0, Key
->Value
);
940 DPRINT(" creating key\n" );
942 Key
->Value
= HeapAlloc(GetProcessHeap(), 0, (wcslen(Value
) + 1) * sizeof(WCHAR
));
943 wcscpy(Key
->Value
, Value
);
944 CurProfile
->Changed
= TRUE
;
950 * if AllowSectionNameCopy is TRUE, allow the copying :
951 * - of Section names if 'section' is NULL
952 * - of Keys in a Section if 'entry' is NULL
953 * (see MSDN doc for GetPrivateProfileString)
956 PROFILE_GetPrivateProfileString(LPCWSTR Section
, LPCWSTR Entry
,
957 LPCWSTR DefVal
, LPWSTR Buffer
,
958 UINT Len
, LPCWSTR Filename
,
959 BOOL AllowSectionNameCopy
)
962 LPWSTR pDefVal
= NULL
;
964 if (NULL
== Filename
)
966 Filename
= L
"win.ini";
969 DPRINT("%S,%S,%S,%p,%u,%S\n", Section
, Entry
, DefVal
, Buffer
, Len
, Filename
);
971 /* strip any trailing ' ' of DefVal. */
974 LPCWSTR p
= &DefVal
[wcslen(DefVal
)]; /* even "" works ! */
984 if (' ' == *p
) /* ouch, contained trailing ' ' */
986 int NewLen
= (int)(p
- DefVal
);
987 pDefVal
= HeapAlloc(GetProcessHeap(), 0, (NewLen
+ 1) * sizeof(WCHAR
));
988 wcsncpy(pDefVal
, DefVal
, NewLen
);
995 pDefVal
= (LPWSTR
) DefVal
;
998 RtlEnterCriticalSection(&ProfileLock
);
1000 if (PROFILE_Open(Filename
))
1002 if ((AllowSectionNameCopy
) && (NULL
== Section
))
1004 Ret
= PROFILE_GetSectionNames(Buffer
, Len
);
1008 /* PROFILE_GetString already handles the 'entry == NULL' case */
1009 Ret
= PROFILE_GetString(Section
, Entry
, pDefVal
, Buffer
, Len
);
1014 lstrcpynW(Buffer
, pDefVal
, Len
);
1015 Ret
= wcslen(Buffer
);
1018 RtlLeaveCriticalSection(&ProfileLock
);
1020 if (pDefVal
!= DefVal
) /* allocated */
1022 HeapFree(GetProcessHeap(), 0, pDefVal
);
1025 DPRINT("returning %S, %d\n", Buffer
, Ret
);
1036 RtlInitializeCriticalSection(&ProfileLock
);
1038 for (i
= 0; i
< N_CACHED_PROFILES
; i
++)
1040 MRUProfile
[i
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PROFILE
));
1041 if (NULL
== MRUProfile
[i
])
1045 MRUProfile
[i
]->Changed
= FALSE
;
1046 MRUProfile
[i
]->Section
= NULL
;
1047 MRUProfile
[i
]->FullName
= NULL
;
1048 MRUProfile
[i
]->LastWriteTime
.dwLowDateTime
= 0;
1049 MRUProfile
[i
]->LastWriteTime
.dwHighDateTime
= 0;
1059 CloseProfileUserMapping(VOID
)
1061 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1070 GetPrivateProfileIntW(
1078 UNICODE_STRING BufferW
;
1082 if (0 == (Len
= GetPrivateProfileStringW(AppName
, KeyName
, L
"",
1083 Buffer
, sizeof(Buffer
)/sizeof(WCHAR
),
1086 return (UINT
) Default
;
1089 if (Len
+ 1 == sizeof(Buffer
) / sizeof(WCHAR
))
1091 DPRINT1("Result may be wrong!\n");
1094 /* FIXME: if entry can be found but it's empty, then Win16 is
1095 * supposed to return 0 instead of def_val ! Difficult/problematic
1096 * to implement (every other failure also returns zero buffer),
1097 * thus wait until testing framework avail for making sure nothing
1098 * else gets broken that way. */
1099 if (L
'\0' == Buffer
[0])
1101 return (UINT
) Default
;
1104 RtlInitUnicodeString(&BufferW
, Buffer
);
1105 RtlUnicodeStringToInteger(&BufferW
, 10, &Result
);
1115 GetPrivateProfileIntA(
1122 UNICODE_STRING KeyNameW
, FileNameW
, AppNameW
;
1125 if (NULL
!= KeyName
)
1127 RtlCreateUnicodeStringFromAsciiz(&KeyNameW
, (PCSZ
) KeyName
);
1131 KeyNameW
.Buffer
= NULL
;
1133 if (NULL
!= FileName
)
1135 RtlCreateUnicodeStringFromAsciiz(&FileNameW
, (PCSZ
) FileName
);
1139 FileNameW
.Buffer
= NULL
;
1141 if (NULL
!= AppName
)
1143 RtlCreateUnicodeStringFromAsciiz(&AppNameW
, (PCSZ
) AppName
);
1147 AppNameW
.Buffer
= NULL
;
1150 Res
= GetPrivateProfileIntW(AppNameW
.Buffer
, KeyNameW
.Buffer
, Default
,
1153 RtlFreeUnicodeString(&AppNameW
);
1154 RtlFreeUnicodeString(&FileNameW
);
1155 RtlFreeUnicodeString(&KeyNameW
);
1165 GetPrivateProfileSectionW (
1167 LPWSTR lpReturnedString
,
1172 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1181 GetPrivateProfileSectionA (
1183 LPSTR lpReturnedString
,
1188 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1193 /***********************************************************************
1194 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1196 * Returns the section names contained in the specified file.
1197 * The section names are returned as a list of strings with an extra
1198 * '\0' to mark the end of the list.
1200 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1201 * '\0' and the return value is 0
1202 * - otherwise if the buffer is too small then the first section name that
1203 * does not fit is truncated so that the string list can be terminated
1204 * correctly (double '\0')
1205 * - the return value is the number of characters written in the buffer
1206 * except for the trailing '\0'. If the buffer is too small, then the
1207 * return value is len-2
1208 * - Win2000 has a bug that triggers when the section names and the
1209 * trailing '\0' fit exactly in the buffer. In that case the trailing
1212 * Note that when the buffer is big enough then the return value may be any
1213 * value between 1 and len-1 , including len-2.
1218 GetPrivateProfileSectionNamesW(
1226 RtlEnterCriticalSection(&ProfileLock
);
1228 if (PROFILE_Open(FileName
))
1230 Ret
= PROFILE_GetSectionNames(Buffer
, Size
);
1233 RtlLeaveCriticalSection(&ProfileLock
);
1243 GetPrivateProfileSectionNamesA(
1249 UNICODE_STRING FileNameW
;
1253 BufferW
= Buffer
? HeapAlloc(GetProcessHeap(), 0, Size
* sizeof(WCHAR
)) : NULL
;
1254 if (NULL
!= FileName
)
1256 RtlCreateUnicodeStringFromAsciiz(&FileNameW
, (PCSZ
) FileName
);
1260 FileNameW
.Buffer
= NULL
;
1263 RetW
= GetPrivateProfileSectionNamesW(BufferW
, Size
, FileNameW
.Buffer
);
1264 if (0 != RetW
&& 0 != Size
)
1266 Ret
= WideCharToMultiByte(CP_ACP
, 0, BufferW
, RetW
, Buffer
, Size
, NULL
, NULL
);
1270 Buffer
[Size
- 1] = '\0';
1274 RtlFreeUnicodeString(&FileNameW
);
1275 if (NULL
!= BufferW
)
1277 HeapFree(GetProcessHeap(), 0, BufferW
);
1288 GetPrivateProfileStringW(
1292 LPWSTR ReturnedString
,
1297 return PROFILE_GetPrivateProfileString(AppName
, KeyName
, Default
,
1298 ReturnedString
, Size
, FileName
, TRUE
);
1306 GetPrivateProfileStringA(
1310 LPSTR ReturnedString
,
1315 UNICODE_STRING AppNameW
, KeyNameW
, DefaultW
, FileNameW
;
1316 LPWSTR ReturnedStringW
;
1319 ReturnedStringW
= (NULL
!= ReturnedString
1320 ? HeapAlloc(GetProcessHeap(), 0, Size
* sizeof(WCHAR
)) : NULL
);
1321 if (NULL
!= AppName
)
1323 RtlCreateUnicodeStringFromAsciiz(&AppNameW
, (PCSZ
) AppName
);
1327 AppNameW
.Buffer
= NULL
;
1329 if (NULL
!= KeyName
)
1331 RtlCreateUnicodeStringFromAsciiz(&KeyNameW
, (PCSZ
) KeyName
);
1335 KeyNameW
.Buffer
= NULL
;
1337 if (NULL
!= Default
)
1339 RtlCreateUnicodeStringFromAsciiz(&DefaultW
, (PCSZ
) Default
);
1343 DefaultW
.Buffer
= NULL
;
1345 if (NULL
!= FileName
)
1347 RtlCreateUnicodeStringFromAsciiz(&FileNameW
, (PCSZ
) FileName
);
1351 FileNameW
.Buffer
= NULL
;
1354 RetW
= GetPrivateProfileStringW(AppNameW
.Buffer
, KeyNameW
.Buffer
,
1355 DefaultW
.Buffer
, ReturnedStringW
, Size
,
1359 Ret
= WideCharToMultiByte(CP_ACP
, 0, ReturnedStringW
, RetW
+ 1, ReturnedString
, Size
, NULL
, NULL
);
1363 ReturnedString
[Ret
] = 0;
1367 Ret
--; /* strip terminating 0 */
1371 RtlFreeUnicodeString(&AppNameW
);
1372 RtlFreeUnicodeString(&KeyNameW
);
1373 RtlFreeUnicodeString(&DefaultW
);
1374 RtlFreeUnicodeString(&FileNameW
);
1375 if (NULL
!= ReturnedStringW
)
1377 HeapFree(GetProcessHeap(), 0, ReturnedStringW
);
1388 GetPrivateProfileStructW (
1396 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1405 GetPrivateProfileStructA (
1413 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1422 GetProfileIntW(LPCWSTR lpAppName
,
1426 return GetPrivateProfileIntW(lpAppName
,
1437 GetProfileIntA(LPCSTR lpAppName
,
1441 return GetPrivateProfileIntA(lpAppName
,
1452 GetProfileSectionW(LPCWSTR lpAppName
,
1453 LPWSTR lpReturnedString
,
1456 return GetPrivateProfileSectionW(lpAppName
,
1467 GetProfileSectionA(LPCSTR lpAppName
,
1468 LPSTR lpReturnedString
,
1471 return GetPrivateProfileSectionA(lpAppName
,
1482 GetProfileStringW(LPCWSTR lpAppName
,
1485 LPWSTR lpReturnedString
,
1488 return GetPrivateProfileStringW(lpAppName
,
1501 GetProfileStringA(LPCSTR lpAppName
,
1504 LPSTR lpReturnedString
,
1507 return GetPrivateProfileStringA(lpAppName
,
1520 OpenProfileUserMapping (VOID
)
1522 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1531 QueryWin31IniFilesMappedToRegistry (
1538 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1547 WritePrivateProfileSectionA (
1553 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1562 WritePrivateProfileSectionW (
1568 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1577 WritePrivateProfileStringA(LPCSTR AppName
,
1582 UNICODE_STRING AppNameW
, KeyNameW
, StringW
, FileNameW
;
1585 if (NULL
!= AppName
)
1587 RtlCreateUnicodeStringFromAsciiz(&AppNameW
, (PCSZ
) AppName
);
1591 AppNameW
.Buffer
= NULL
;
1593 if (NULL
!= KeyName
)
1595 RtlCreateUnicodeStringFromAsciiz(&KeyNameW
, (PCSZ
) KeyName
);
1599 KeyNameW
.Buffer
= NULL
;
1603 RtlCreateUnicodeStringFromAsciiz(&StringW
, (PCSZ
) String
);
1607 StringW
.Buffer
= NULL
;
1609 if (NULL
!= FileName
)
1611 RtlCreateUnicodeStringFromAsciiz(&FileNameW
, (PCSZ
) FileName
);
1615 FileNameW
.Buffer
= NULL
;
1618 Ret
= WritePrivateProfileStringW(AppNameW
.Buffer
, KeyNameW
.Buffer
,
1619 StringW
.Buffer
, FileNameW
.Buffer
);
1621 RtlFreeUnicodeString(&AppNameW
);
1622 RtlFreeUnicodeString(&KeyNameW
);
1623 RtlFreeUnicodeString(&StringW
);
1624 RtlFreeUnicodeString(&FileNameW
);
1634 WritePrivateProfileStringW(LPCWSTR AppName
,
1641 RtlEnterCriticalSection(&ProfileLock
);
1643 if (PROFILE_Open(FileName
))
1645 if (NULL
== AppName
&& NULL
== KeyName
&& NULL
== String
) /* documented "file flush" case */
1647 PROFILE_FlushFile();
1648 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1652 if (NULL
== AppName
)
1654 DPRINT1("(NULL?,%s,%s,%s)?\n", KeyName
, String
, FileName
);
1658 Ret
= PROFILE_SetString(AppName
, KeyName
, String
, FALSE
);
1659 PROFILE_FlushFile();
1664 RtlLeaveCriticalSection(&ProfileLock
);
1674 WritePrivateProfileStructA (
1682 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1691 WritePrivateProfileStructW (
1699 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1708 WriteProfileSectionA(LPCSTR lpAppName
,
1711 return WritePrivateProfileSectionA(lpAppName
,
1721 WriteProfileSectionW(LPCWSTR lpAppName
,
1724 return WritePrivateProfileSectionW(lpAppName
,
1734 WriteProfileStringA(LPCSTR AppName
,
1738 return WritePrivateProfileStringA(AppName
,
1749 WriteProfileStringW(LPCWSTR AppName
,
1753 return WritePrivateProfileStringW(AppName
,