Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
April 2019
- 82 participants
- 1927 messages
[PATCH] ntdll: Initialize critical section debug info with correct pointer value.
by Nikolay Sivov
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=39614
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/kernel32/sync.c | 3 ++-
dlls/kernel32/tests/sync.c | 14 +++++++++++-
dlls/ntdll/critsection.c | 44 ++++++++++++++++++++++----------------
3 files changed, 41 insertions(+), 20 deletions(-)
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index 6d47d7004c..9f5b614508 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -402,7 +402,8 @@ void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
HANDLE sem = crit->LockSemaphore;
if (!sem) NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 );
crit->LockSemaphore = ConvertToGlobalHandle( sem );
- RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo );
+ if (crit->DebugInfo != (void *)(ULONG_PTR)-1)
+ RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo );
crit->DebugInfo = NULL;
}
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c
index 188689a9f4..97566f1d84 100644
--- a/dlls/kernel32/tests/sync.c
+++ b/dlls/kernel32/tests/sync.c
@@ -2648,6 +2648,7 @@ static void test_crit_section(void)
InitializeCriticalSection(&cs);
ok(cs.DebugInfo != NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
DeleteCriticalSection(&cs);
+ ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
if (!pInitializeCriticalSectionEx)
{
@@ -2658,9 +2659,20 @@ static void test_crit_section(void)
memset(&cs, 0, sizeof(cs));
ret = pInitializeCriticalSectionEx(&cs, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
ok(ret, "Failed to initialize critical section.\n");
-todo_wine
ok(cs.DebugInfo == (void *)(ULONG_PTR)-1, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
+
+ ret = TryEnterCriticalSection(&cs);
+ ok(ret, "Failed to enter critical section.\n");
+ LeaveCriticalSection(&cs);
+
+ cs.DebugInfo = NULL;
+
+ ret = TryEnterCriticalSection(&cs);
+ ok(ret, "Failed to enter critical section.\n");
+ LeaveCriticalSection(&cs);
+
DeleteCriticalSection(&cs);
+ ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
}
START_TEST(sync)
diff --git a/dlls/ntdll/critsection.c b/dlls/ntdll/critsection.c
index 42e432c8f6..e8ffc1ceed 100644
--- a/dlls/ntdll/critsection.c
+++ b/dlls/ntdll/critsection.c
@@ -59,6 +59,13 @@ static inline void small_pause(void)
#endif
}
+static void *no_debug_info_marker = (void *)(ULONG_PTR)-1;
+
+static BOOL crit_section_has_debuginfo(const RTL_CRITICAL_SECTION *crit)
+{
+ return crit->DebugInfo != NULL && crit->DebugInfo != no_debug_info_marker;
+}
+
#ifdef __linux__
static int wait_op = 128; /*FUTEX_WAIT|FUTEX_PRIVATE_FLAG*/
@@ -226,7 +233,7 @@ static inline NTSTATUS wait_semaphore( RTL_CRITICAL_SECTION *crit, int timeout )
NTSTATUS ret;
/* debug info is cleared by MakeCriticalSectionGlobal */
- if (!crit->DebugInfo || ((ret = fast_wait( crit, timeout )) == STATUS_NOT_IMPLEMENTED))
+ if (!crit_section_has_debuginfo( crit ) || ((ret = fast_wait( crit, timeout )) == STATUS_NOT_IMPLEMENTED))
{
HANDLE sem = get_semaphore( crit );
LARGE_INTEGER time;
@@ -321,20 +328,21 @@ NTSTATUS WINAPI RtlInitializeCriticalSectionEx( RTL_CRITICAL_SECTION *crit, ULON
* so (e.g.) MakeCriticalSectionGlobal() doesn't free it using HeapFree().
*/
if (flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO)
- crit->DebugInfo = NULL;
+ crit->DebugInfo = no_debug_info_marker;
else
- crit->DebugInfo = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_CRITICAL_SECTION_DEBUG));
-
- if (crit->DebugInfo)
{
- crit->DebugInfo->Type = 0;
- crit->DebugInfo->CreatorBackTraceIndex = 0;
- crit->DebugInfo->CriticalSection = crit;
- crit->DebugInfo->ProcessLocksList.Blink = &(crit->DebugInfo->ProcessLocksList);
- crit->DebugInfo->ProcessLocksList.Flink = &(crit->DebugInfo->ProcessLocksList);
- crit->DebugInfo->EntryCount = 0;
- crit->DebugInfo->ContentionCount = 0;
- memset( crit->DebugInfo->Spare, 0, sizeof(crit->DebugInfo->Spare) );
+ crit->DebugInfo = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_CRITICAL_SECTION_DEBUG));
+ if (crit->DebugInfo)
+ {
+ crit->DebugInfo->Type = 0;
+ crit->DebugInfo->CreatorBackTraceIndex = 0;
+ crit->DebugInfo->CriticalSection = crit;
+ crit->DebugInfo->ProcessLocksList.Blink = &(crit->DebugInfo->ProcessLocksList);
+ crit->DebugInfo->ProcessLocksList.Flink = &(crit->DebugInfo->ProcessLocksList);
+ crit->DebugInfo->EntryCount = 0;
+ crit->DebugInfo->ContentionCount = 0;
+ memset( crit->DebugInfo->Spare, 0, sizeof(crit->DebugInfo->Spare) );
+ }
}
crit->LockCount = -1;
crit->RecursionCount = 0;
@@ -396,7 +404,7 @@ NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
crit->LockCount = -1;
crit->RecursionCount = 0;
crit->OwningThread = 0;
- if (crit->DebugInfo)
+ if (crit_section_has_debuginfo( crit ))
{
/* only free the ones we made in here */
if (!crit->DebugInfo->Spare[0])
@@ -454,7 +462,7 @@ NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit )
if ( status == STATUS_TIMEOUT )
{
const char *name = NULL;
- if (crit->DebugInfo) name = (char *)crit->DebugInfo->Spare[0];
+ if (crit_section_has_debuginfo( crit )) name = (char *)crit->DebugInfo->Spare[0];
if (!name) name = "?";
ERR( "section %p %s wait timed out in thread %04x, blocked by %04x, retrying (60 sec)\n",
crit, debugstr_a(name), GetCurrentThreadId(), HandleToULong(crit->OwningThread) );
@@ -472,7 +480,7 @@ NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit )
if (status == STATUS_WAIT_0) break;
/* Throw exception only for Wine internal locks */
- if ((!crit->DebugInfo) || (!crit->DebugInfo->Spare[0])) continue;
+ if (!crit_section_has_debuginfo( crit ) || !crit->DebugInfo->Spare[0]) continue;
/* only throw deadlock exception if configured timeout is reached */
if (timeout > 0) continue;
@@ -485,7 +493,7 @@ NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit )
rec.ExceptionInformation[0] = (ULONG_PTR)crit;
RtlRaiseException( &rec );
}
- if (crit->DebugInfo) crit->DebugInfo->ContentionCount++;
+ if (crit_section_has_debuginfo( crit )) crit->DebugInfo->ContentionCount++;
return STATUS_SUCCESS;
}
@@ -518,7 +526,7 @@ NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
NTSTATUS ret;
/* debug info is cleared by MakeCriticalSectionGlobal */
- if (!crit->DebugInfo || ((ret = fast_wake( crit )) == STATUS_NOT_IMPLEMENTED))
+ if (!crit_section_has_debuginfo( crit ) || ((ret = fast_wake( crit )) == STATUS_NOT_IMPLEMENTED))
{
HANDLE sem = get_semaphore( crit );
ret = NtReleaseSemaphore( sem, 1, NULL );
--
2.20.1
April 30, 2019
Re: [PATCH 2/2] kernel32: Split A/W implementation of {Get,Write}PrivateProfileString().
by Dmitry Timoshkov
Jactry Zeng <jzeng(a)codeweavers.com> wrote:
> On 2019/4/30 下午2:05, Dmitry Timoshkov wrote:
> > Please add the convincing set of the tests first to show the problem, at
> > the moment I fail to see what exactly you are trying trying to fix, and
> > only then try to think about the possible ways to fix the spotted bug(s).
>
> I think the tests already exposed some problems, some applications were trying to use GetPrivateProfileStringA() for getting values from an UTF-8 profile.
>
> Attachment is an independent testcase. On Windows, printing out result isn't locale related(I tested it on English and Chinese Windows). But on current Wine, the result is locale related.
> For example: $ LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8 wine test_GetPrivateProfileStringA.exe will print out:
>
> ffffffe4 ffffffb8 003f
>
> when on Wine with en_US.UTF-8 and on Windows it was:
>
> ffffffe4 ffffffb8 ffffff8a 003a
>
> I'm quite not sure how to fix it correctly, any thoughts or suggest will be appreciated.
As usually the very first thing to do is to add minimal test case that shows
the problem, that way it would be clearer what is going on.
--
Dmitry.
April 30, 2019
Re: [PATCH 2/2] kernel32: Split A/W implementation of {Get,Write}PrivateProfileString().
by Jactry Zeng
Hi Dmitry,
Thanks for review and comment.
On 2019/4/30 下午2:05, Dmitry Timoshkov wrote:
> Please add the convincing set of the tests first to show the problem, at
> the moment I fail to see what exactly you are trying trying to fix, and
> only then try to think about the possible ways to fix the spotted bug(s).
I think the tests already exposed some problems, some applications were trying to use GetPrivateProfileStringA() for getting values from an UTF-8 profile.
Attachment is an independent testcase. On Windows, printing out result isn't locale related(I tested it on English and Chinese Windows). But on current Wine, the result is locale related.
For example: $ LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8 wine test_GetPrivateProfileStringA.exe will print out:
ffffffe4 ffffffb8 003f
when on Wine with en_US.UTF-8 and on Windows it was:
ffffffe4 ffffffb8 ffffff8a 003a
I'm quite not sure how to fix it correctly, any thoughts or suggest will be appreciated.
April 30, 2019
Re: Issues with new fake DLLs
by Alexandre Julliard
Sveinar Søpler <cybermax(a)dexter.no> writes:
> ----- On Apr 30, 2019, at 7:35 AM, Derek Lesho <dereklesho52(a)gmail.com> wrote:
>
> Hello, while working with EAC, I tracked down an error to EAC requiring the ntdll.dll it has read from system32 being over 4095 bytes in size. For some reason, it seems that the fake dlls have recently dropped in size, and consist of only a header. EAC also reads the export table later on and checks for
> mov instructions that are present in the old fake DLLs.
>
> Could this possibly be related to something with MinGW? Around
> wine-4.4/4.5 MinGW was "enabled" for some cross-compile of PE-files
> (fake-dll's perhaps is compiled with MinGW?). I have not really
> studied it, and stopped using it due to various errors with recent
> wine (latest was some build problems with MinGW enabled).
The plan is to build fake dlls with MinGW, but that's not enabled yet.
At this point nothing has changed. The fake dlls that contain an export
table were most likely generated by wine-staging. Main wine doesn't do
that yet.
--
Alexandre Julliard
julliard(a)winehq.org
April 30, 2019
Re: Issues with new fake DLLs
by Sveinar Søpler
----- On Apr 30, 2019, at 7:35 AM, Derek Lesho <dereklesho52(a)gmail.com> wrote:
> Hello, while working with EAC, I tracked down an error to EAC requiring the
> ntdll.dll it has read from system32 being over 4095 bytes in size. For some
> reason, it seems that the fake dlls have recently dropped in size, and consist
> of only a header. EAC also reads the export table later on and checks for mov
> instructions that are present in the old fake DLLs.
Could this possibly be related to something with MinGW? Around wine-4.4/4.5 MinGW was "enabled" for some cross-compile of PE-files (fake-dll's perhaps is compiled with MinGW?). I have not really studied it, and stopped using it due to various errors with recent wine (latest was some build problems with MinGW enabled).
Could you perhaps try to use the " --without-mingw" configure option if you compile yourself?
If you use the WineHQ pre-compiled binaries, i think this is compiled without using MinGW (atleast for Debian based distros).
Sveinar
April 30, 2019
Re: [PATCH 2/2] kernel32: Split A/W implementation of {Get,Write}PrivateProfileString().
by Dmitry Timoshkov
Jactry Zeng <jzeng(a)codeweavers.com> wrote:
> +static LPWSTR c2w(LPCSTR string)
> +{
> + INT lenW;
> + LPWSTR stringW = NULL;
> +
> + if (!string)
> + return stringW;
> +
> + lenW = MultiByteToWideChar(1252, 0, string, -1, NULL, 0);
> + if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR))))
> + MultiByteToWideChar(1252, 0, string, -1, stringW, lenW);
> + return stringW;
> +}
As mentioned before tis will break a lot of apps that write profile strings
using system locale.
> @@ -1189,7 +1272,11 @@ START_TEST(profile)
> "name2=\"val2\"\r\n"
> "name3\r\n"
> "name4=a\r\n"
> - "[section2]\r\n",
> + "[section2]\r\n"
> + "[\xe6\xae\xb5\x31]\r\n" /* Simplified Chinese in UTF-8 */
> + "name5=\xe9\x85\x92\x2e\r\n" /* Simplified Chinese in UTF-8 */
> + "\xe5\xa7\x93=\xe6\x9b\xbe\x2e\r\n" /* Simplified Chinese in UTF-8 */
> + "name6=\xd7\x99\xd7\x99\xd7\x9f\x2e\r\n", /* Hebrew in UTF-8 */
> "CR+LF");
> test_GetPrivateProfileString(
> "[section1]\r"
> @@ -1197,7 +1284,11 @@ START_TEST(profile)
> "name2=\"val2\"\r"
> "name3\r"
> "name4=a\r"
> - "[section2]\r",
> + "[section2]\r"
> + "[\xe6\xae\xb5\x31]\r" /* Simplified Chinese in UTF-8 */
> + "name5=\xe9\x85\x92\x2e\r" /* Simplified Chinese in UTF-8 */
> + "\xe5\xa7\x93=\xe6\x9b\xbe\x2e\r" /* Simplified Chinese in UTF-8 */
> + "name6=\xd7\x99\xd7\x99\xd7\x9f\x2e\r", /* Hebrew in UTF-8 */
Why are you testing with UTF-8 encoded strings but the implementation
uses code page 1252? This is clearly broken.
Please add the convincing set of the tests first to show the problem, at
the moment I fail to see what exactly you are trying trying to fix, and
only then try to think about the possible ways to fix the spotted bug(s).
--
Dmitry.
April 30, 2019
Re: [PATCH 1/2] kernel32: Move implementation of {Get, Write}PrivateProfileStringW() to helper.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=51618
Your paranoid android.
=== debian9 (64 bit WoW report) ===
kernel32:
change.c:320: Test failed: should be ready
April 30, 2019
Issues with new fake DLLs
by Derek Lesho
Hello, while working with EAC, I tracked down an error to EAC requiring the
ntdll.dll it has read from system32 being over 4095 bytes in size. For
some reason, it seems that the fake dlls have recently dropped in size, and
consist of only a header. EAC also reads the export table later on and
checks for mov instructions that are present in the old fake DLLs.
April 30, 2019
Re: [PATCH v4 3/3] po: Add Asturian translation
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=51616
Your paranoid android.
=== debian9 (32 bit report) ===
kernel32:
loader.c:3850: Test failed: kernel32.dll:2: wrong OptionalHeader.DataDirectory[i].Size 1b9660 / 1ae3dc
loader.c:3850: Test failed: user32.dll:2: wrong OptionalHeader.DataDirectory[i].Size e4818 / e4274
=== debian9 (32 bit Chinese:China report) ===
kernel32:
loader.c:3850: Test failed: kernel32.dll:2: wrong OptionalHeader.DataDirectory[i].Size 1b9660 / 1ae3dc
loader.c:3850: Test failed: user32.dll:2: wrong OptionalHeader.DataDirectory[i].Size e4818 / e4274
=== debian9 (32 bit WoW report) ===
kernel32:
loader.c:3850: Test failed: kernel32.dll:2: wrong OptionalHeader.DataDirectory[i].Size 1b9660 / 1ae3dc
loader.c:3850: Test failed: user32.dll:2: wrong OptionalHeader.DataDirectory[i].Size e4818 / e4274
=== debian9 (64 bit WoW report) ===
kernel32:
loader.c:3850: Test failed: kernel32.dll:2: wrong OptionalHeader.DataDirectory[i].Size 1b9660 / 1ae3dc
loader.c:3850: Test failed: user32.dll:2: wrong OptionalHeader.DataDirectory[i].Size e4818 / e4274
April 30, 2019
[PATCH 2/2] kernel32: Split A/W implementation of {Get,Write}PrivateProfileString().
by Jactry Zeng
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
dlls/kernel32/profile.c | 126 +++++++++++++++++++---------------
dlls/kernel32/tests/profile.c | 109 ++++++++++++++++++++++++++---
2 files changed, 169 insertions(+), 66 deletions(-)
diff --git a/dlls/kernel32/profile.c b/dlls/kernel32/profile.c
index 462d64e5f0..3defaf6bef 100644
--- a/dlls/kernel32/profile.c
+++ b/dlls/kernel32/profile.c
@@ -68,6 +68,7 @@ typedef struct
WCHAR *filename;
FILETIME LastWriteTime;
ENCODING encoding;
+ BOOL is_unicode;
} PROFILE;
@@ -149,7 +150,7 @@ static inline void PROFILE_WriteMarker(HANDLE hFile, ENCODING encoding)
}
}
-static void PROFILE_WriteLine( HANDLE hFile, WCHAR * szLine, int len, ENCODING encoding)
+static void PROFILE_WriteLine(HANDLE hFile, WCHAR *szLine, int len, ENCODING encoding, BOOL is_unicode)
{
char * write_buffer;
int write_buffer_len;
@@ -160,10 +161,10 @@ static void PROFILE_WriteLine( HANDLE hFile, WCHAR * szLine, int len, ENCODING e
switch (encoding)
{
case ENCODING_ANSI:
- write_buffer_len = WideCharToMultiByte(CP_ACP, 0, szLine, len, NULL, 0, NULL, NULL);
+ write_buffer_len = WideCharToMultiByte(is_unicode ? CP_ACP : 1252, 0, szLine, len, NULL, 0, NULL, NULL);
write_buffer = HeapAlloc(GetProcessHeap(), 0, write_buffer_len);
if (!write_buffer) return;
- len = WideCharToMultiByte(CP_ACP, 0, szLine, len, write_buffer, write_buffer_len, NULL, NULL);
+ len = WideCharToMultiByte(is_unicode ? CP_ACP : 1252, 0, szLine, len, write_buffer, write_buffer_len, NULL, NULL);
WriteFile(hFile, write_buffer, len, &dwBytesWritten, NULL);
HeapFree(GetProcessHeap(), 0, write_buffer);
break;
@@ -192,7 +193,7 @@ static void PROFILE_WriteLine( HANDLE hFile, WCHAR * szLine, int len, ENCODING e
*
* Save a profile tree to a file.
*/
-static void PROFILE_Save( HANDLE hFile, const PROFILESECTION *section, ENCODING encoding )
+static void PROFILE_Save(HANDLE hFile, const PROFILESECTION *section, ENCODING encoding, BOOL is_unicode)
{
PROFILEKEY *key;
WCHAR *buffer, *p;
@@ -238,7 +239,7 @@ static void PROFILE_Save( HANDLE hFile, const PROFILESECTION *section, ENCODING
*p++ = '\r';
*p++ = '\n';
}
- PROFILE_WriteLine( hFile, buffer, len, encoding );
+ PROFILE_WriteLine(hFile, buffer, len, encoding, is_unicode);
HeapFree(GetProcessHeap(), 0, buffer);
}
}
@@ -305,7 +306,7 @@ static inline ENCODING PROFILE_DetectTextEncoding(const void * buffer, int * len
*
* Load a profile tree from a file.
*/
-static PROFILESECTION *PROFILE_Load(HANDLE hFile, ENCODING * pEncoding)
+static PROFILESECTION *PROFILE_Load(HANDLE hFile, ENCODING *pEncoding, BOOL is_unicode)
{
void *buffer_base, *pBuffer;
WCHAR * szFile;
@@ -343,14 +344,14 @@ static PROFILESECTION *PROFILE_Load(HANDLE hFile, ENCODING * pEncoding)
case ENCODING_ANSI:
TRACE("ANSI encoding\n");
- len = MultiByteToWideChar(CP_ACP, 0, pBuffer, dwFileSize, NULL, 0);
+ len = MultiByteToWideChar(is_unicode ? CP_ACP : 1252, 0, pBuffer, dwFileSize, NULL, 0);
szFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!szFile)
{
HeapFree(GetProcessHeap(), 0, buffer_base);
return NULL;
}
- MultiByteToWideChar(CP_ACP, 0, pBuffer, dwFileSize, szFile, len);
+ MultiByteToWideChar(is_unicode ? CP_ACP : 1252, 0, pBuffer, dwFileSize, szFile, len);
szEnd = szFile + len;
break;
case ENCODING_UTF8:
@@ -678,7 +679,7 @@ static BOOL PROFILE_FlushFile(void)
}
TRACE("Saving %s\n", debugstr_w(CurProfile->filename));
- PROFILE_Save( hFile, CurProfile->section, CurProfile->encoding );
+ PROFILE_Save(hFile, CurProfile->section, CurProfile->encoding, CurProfile->is_unicode);
if(GetFileTime(hFile, NULL, NULL, &LastWriteTime))
CurProfile->LastWriteTime=LastWriteTime;
CloseHandle( hFile );
@@ -729,7 +730,7 @@ static BOOL is_not_current(FILETIME * ft)
*
* Open a profile file, checking the cached file first.
*/
-static BOOL PROFILE_Open( LPCWSTR filename, BOOL write_access )
+static BOOL PROFILE_Open(LPCWSTR filename, BOOL write_access, BOOL is_unicode)
{
WCHAR buffer[MAX_PATH];
HANDLE hFile = INVALID_HANDLE_VALUE;
@@ -750,6 +751,7 @@ static BOOL PROFILE_Open( LPCWSTR filename, BOOL write_access )
MRUProfile[i]->section=NULL;
MRUProfile[i]->filename=NULL;
MRUProfile[i]->encoding=ENCODING_ANSI;
+ MRUProfile[i]->is_unicode = is_unicode;
ZeroMemory(&MRUProfile[i]->LastWriteTime, sizeof(FILETIME));
}
@@ -786,7 +788,8 @@ static BOOL PROFILE_Open( LPCWSTR filename, BOOL write_access )
for(i=0;i<N_CACHED_PROFILES;i++)
{
- if ((MRUProfile[i]->filename && !strcmpiW( buffer, MRUProfile[i]->filename )))
+ if ((MRUProfile[i]->filename && !strcmpiW(buffer, MRUProfile[i]->filename) &&
+ (MRUProfile[i]->is_unicode == is_unicode)))
{
TRACE("MRU Filename: %s, new filename: %s\n", debugstr_w(MRUProfile[i]->filename), debugstr_w(buffer));
if(i)
@@ -810,7 +813,7 @@ static BOOL PROFILE_Open( LPCWSTR filename, BOOL write_access )
TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
debugstr_w(buffer), i);
PROFILE_Free(CurProfile->section);
- CurProfile->section = PROFILE_Load(hFile, &CurProfile->encoding);
+ CurProfile->section = PROFILE_Load(hFile, &CurProfile->encoding, CurProfile->is_unicode);
CurProfile->LastWriteTime = LastWriteTime;
}
CloseHandle(hFile);
@@ -840,7 +843,8 @@ static BOOL PROFILE_Open( LPCWSTR filename, BOOL write_access )
if (hFile != INVALID_HANDLE_VALUE)
{
- CurProfile->section = PROFILE_Load(hFile, &CurProfile->encoding);
+ CurProfile->is_unicode = is_unicode;
+ CurProfile->section = PROFILE_Load(hFile, &CurProfile->encoding, CurProfile->is_unicode);
GetFileTime(hFile, NULL, NULL, &CurProfile->LastWriteTime);
CloseHandle(hFile);
}
@@ -1062,6 +1066,19 @@ static BOOL PROFILE_SetString( LPCWSTR section_name, LPCWSTR key_name,
return TRUE;
}
+static LPWSTR c2w(LPCSTR string)
+{
+ INT lenW;
+ LPWSTR stringW = NULL;
+
+ if (!string)
+ return stringW;
+
+ lenW = MultiByteToWideChar(1252, 0, string, -1, NULL, 0);
+ if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR))))
+ MultiByteToWideChar(1252, 0, string, -1, stringW, lenW);
+ return stringW;
+}
/********************* API functions **********************************/
@@ -1083,13 +1100,13 @@ UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
}
static int get_private_profile_string(LPCWSTR section, LPCWSTR entry, LPCWSTR def_val,
- LPWSTR buffer, UINT len, LPCWSTR filename)
+ LPWSTR buffer, UINT len, LPCWSTR filename, BOOL is_unicode)
{
int ret;
LPWSTR defval_tmp = NULL;
- TRACE("(%s, %s, %s, %p, %u, %s)\n", debugstr_w(section), debugstr_w(entry),
- debugstr_w(def_val), buffer, len, debugstr_w(filename));
+ TRACE("(%s, %s, %s, %p, %u, %s, %d)\n", debugstr_w(section), debugstr_w(entry),
+ debugstr_w(def_val), buffer, len, debugstr_w(filename), is_unicode);
/* strip any trailing ' ' of def_val. */
if (def_val)
@@ -1112,7 +1129,7 @@ static int get_private_profile_string(LPCWSTR section, LPCWSTR entry, LPCWSTR de
RtlEnterCriticalSection(&PROFILE_CritSect);
- if (PROFILE_Open(filename, FALSE))
+ if (PROFILE_Open(filename, FALSE, is_unicode))
{
if (section == NULL)
ret = PROFILE_GetSectionNames(buffer, len);
@@ -1145,7 +1162,7 @@ INT WINAPI GetPrivateProfileStringW(LPCWSTR section, LPCWSTR entry,
UINT len, LPCWSTR filename)
{
return get_private_profile_string(section, entry, def_val, buffer,
- len, filename);
+ len, filename, TRUE);
}
/***********************************************************************
@@ -1155,39 +1172,35 @@ INT WINAPI GetPrivateProfileStringA(LPCSTR section, LPCSTR entry,
LPCSTR def_val, LPSTR buffer,
UINT len, LPCSTR filename)
{
- UNICODE_STRING sectionW, entryW, def_valW, filenameW;
- LPWSTR bufferW;
+ UNICODE_STRING filenameW;
+ LPWSTR bufferW, sectionW, entryW, def_valW;
INT retW, ret = 0;
bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
- if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
- else sectionW.Buffer = NULL;
- if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
- else entryW.Buffer = NULL;
- if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
- else def_valW.Buffer = NULL;
+ sectionW = c2w(section);
+ entryW = c2w(entry);
+ def_valW = c2w(def_val);
if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
else filenameW.Buffer = NULL;
- retW = get_private_profile_string(sectionW.Buffer, entryW.Buffer,
- def_valW.Buffer, bufferW, len,
- filenameW.Buffer);
+ retW = get_private_profile_string(sectionW, entryW, def_valW, bufferW, len,
+ filenameW.Buffer, FALSE);
if (len && buffer)
{
if (retW)
{
- ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW, buffer, len - 1, NULL, NULL);
+ ret = WideCharToMultiByte(1252, 0, bufferW, retW, buffer, len - 1, NULL, NULL);
if (!ret)
ret = len - 1;
}
buffer[ret] = 0;
}
- RtlFreeUnicodeString(§ionW);
- RtlFreeUnicodeString(&entryW);
- RtlFreeUnicodeString(&def_valW);
RtlFreeUnicodeString(&filenameW);
HeapFree(GetProcessHeap(), 0, bufferW);
+ HeapFree(GetProcessHeap(), 0, sectionW);
+ HeapFree(GetProcessHeap(), 0, entryW);
+ HeapFree(GetProcessHeap(), 0, def_valW);
return ret;
}
@@ -1298,7 +1311,7 @@ INT WINAPI GetPrivateProfileSectionW( LPCWSTR section, LPWSTR buffer,
RtlEnterCriticalSection( &PROFILE_CritSect );
- if (PROFILE_Open( filename, FALSE ))
+ if (PROFILE_Open(filename, FALSE, TRUE))
ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, TRUE);
RtlLeaveCriticalSection( &PROFILE_CritSect );
@@ -1369,23 +1382,23 @@ INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
}
static BOOL write_private_profile_string(LPCWSTR section, LPCWSTR entry, LPCWSTR string,
- LPCWSTR filename)
+ LPCWSTR filename, BOOL is_unicode)
{
BOOL ret = FALSE;
- TRACE("(%s, %s, %s, %s)\n", debugstr_w(section), debugstr_w(entry),
- debugstr_w(string), debugstr_w(filename));
+ TRACE("(%s, %s, %s, %s, %d)\n", debugstr_w(section), debugstr_w(entry),
+ debugstr_w(string), debugstr_w(filename), is_unicode);
RtlEnterCriticalSection(&PROFILE_CritSect);
if (!section && !entry && !string) /* documented "file flush" case */
{
- if (!filename || PROFILE_Open(filename, TRUE))
+ if (!filename || PROFILE_Open(filename, TRUE, is_unicode))
{
if (CurProfile) PROFILE_ReleaseFile(); /* always return FALSE in this case */
}
}
- else if (PROFILE_Open(filename, TRUE))
+ else if (PROFILE_Open(filename, TRUE, is_unicode))
{
if (!section) {
SetLastError(ERROR_FILE_NOT_FOUND);
@@ -1406,7 +1419,7 @@ BOOL WINAPI WritePrivateProfileStringW(LPCWSTR section, LPCWSTR entry,
LPCWSTR string, LPCWSTR filename)
{
return write_private_profile_string(section, entry, string,
- filename);
+ filename, TRUE);
}
/***********************************************************************
@@ -1415,23 +1428,22 @@ BOOL WINAPI WritePrivateProfileStringW(LPCWSTR section, LPCWSTR entry,
BOOL WINAPI DECLSPEC_HOTPATCH WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
LPCSTR string, LPCSTR filename )
{
- UNICODE_STRING sectionW, entryW, stringW, filenameW;
+ UNICODE_STRING filenameW;
+ LPWSTR sectionW, entryW, stringW;
BOOL ret;
- if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section);
- else sectionW.Buffer = NULL;
- if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
- else entryW.Buffer = NULL;
- if (string) RtlCreateUnicodeStringFromAsciiz(&stringW, string);
- else stringW.Buffer = NULL;
+ sectionW = c2w(section);
+ entryW = c2w(entry);
+ stringW = c2w(string);
if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
else filenameW.Buffer = NULL;
- ret = write_private_profile_string(sectionW.Buffer, entryW.Buffer,
- stringW.Buffer, filenameW.Buffer);
- RtlFreeUnicodeString(§ionW);
- RtlFreeUnicodeString(&entryW);
- RtlFreeUnicodeString(&stringW);
+ ret = write_private_profile_string(sectionW, entryW, stringW,
+ filenameW.Buffer, FALSE);
+
+ HeapFree(GetProcessHeap(), 0, sectionW);
+ HeapFree(GetProcessHeap(), 0, entryW);
+ HeapFree(GetProcessHeap(), 0, stringW);
RtlFreeUnicodeString(&filenameW);
return ret;
}
@@ -1449,12 +1461,12 @@ BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
if (!section && !string)
{
- if (!filename || PROFILE_Open( filename, TRUE ))
+ if (!filename || PROFILE_Open(filename, TRUE, TRUE))
{
if (CurProfile) PROFILE_ReleaseFile(); /* always return FALSE in this case */
}
}
- else if (PROFILE_Open( filename, TRUE )) {
+ else if (PROFILE_Open(filename, TRUE, TRUE)) {
if (!string) {/* delete the named section*/
ret = PROFILE_SetString(section,NULL,NULL, FALSE);
} else {
@@ -1576,7 +1588,7 @@ DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
RtlEnterCriticalSection( &PROFILE_CritSect );
- if (PROFILE_Open( filename, FALSE ))
+ if (PROFILE_Open(filename, FALSE, TRUE))
ret = PROFILE_GetSectionNames(buffer, size);
RtlLeaveCriticalSection( &PROFILE_CritSect );
@@ -1631,7 +1643,7 @@ BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
RtlEnterCriticalSection( &PROFILE_CritSect );
- if (PROFILE_Open( filename, FALSE )) {
+ if (PROFILE_Open(filename, FALSE, TRUE)) {
PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
if (k) {
TRACE("value (at %p): %s\n", k->value, debugstr_w(k->value));
@@ -1751,7 +1763,7 @@ BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
RtlEnterCriticalSection( &PROFILE_CritSect );
- if (PROFILE_Open( filename, TRUE )) {
+ if (PROFILE_Open(filename, TRUE, TRUE)) {
ret = PROFILE_SetString( section, key, outstring, FALSE);
if (ret) ret = PROFILE_FlushFile();
}
diff --git a/dlls/kernel32/tests/profile.c b/dlls/kernel32/tests/profile.c
index 8a0089bb1b..761817cb9c 100644
--- a/dlls/kernel32/tests/profile.c
+++ b/dlls/kernel32/tests/profile.c
@@ -592,7 +592,12 @@ static void test_GetPrivateProfileString(const char *content, const char *descri
empty string and check for modification */
CHAR emptystr[MAX_PATH] = "";
LPSTR tempfile;
-
+ WCHAR bufW[MAX_PATH], expected_valW[MAX_PATH];
+ static const WCHAR section_schineseW[] = {0xe6,0xae,0xb5,0x31,0};
+ static const WCHAR name5W[] = {'n','a','m','e','5',0};
+ static const WCHAR filenameW[] = {'.','\\','w','i','n','e','t','e','s','t','.','i','n','i',0};
+ static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0};
+ static const WCHAR expected_val_enW[] = {0x00e9,0x2026,0x2019,'.',0};
static const char filename[] = ".\\winetest.ini";
trace("test_GetPrivateProfileStringA: %s\n", descript);
@@ -620,12 +625,12 @@ static void test_GetPrivateProfileString(const char *content, const char *descri
lstrcpyA(buf, "kumquat");
ret = GetPrivateProfileStringA(NULL, "name1", "default",
buf, MAX_PATH, filename);
- ok(ret == 18 ||
- broken(ret == 19), /* Win9x and WinME */
- "Expected 18, got %d\n", ret);
- len = lstrlenA("section1") + sizeof(CHAR) + lstrlenA("section2") + 2 * sizeof(CHAR);
- ok(!memcmp(buf, "section1\0section2\0\0", len),
- "Expected \"section1\\0section2\\0\\0\", got \"%s\"\n", buf);
+ ok(ret == 23 ||
+ broken(ret == 24), /* Win9x and WinME */
+ "Expected 23, got %d\n", ret);
+ len = lstrlenA("section1") + lstrlenA("section2") + lstrlenA("\xe6\xae\xb5\x31") + 4 * sizeof(CHAR);
+ ok(!memcmp(buf, "section1\0section2\0\xe6\xae\xb5\x31\0\0", len),
+ "Expected \"section1\\0section2\\0\xe6\xae\xb5\x31\\0\\0\", got \"%s\"\n", buf);
/* lpAppName is empty */
memset(buf, 0xc, sizeof(buf));
@@ -827,6 +832,59 @@ static void test_GetPrivateProfileString(const char *content, const char *descri
ok(ret == 0, "Expected 0, got %d\n", ret);
ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
+ memset(buf, 0xc, sizeof(buf));
+ lstrcpyA(buf, "kumquat");
+ ret = GetPrivateProfileStringA("\xe6\xae\xb5\x31", "name5", "default",
+ buf, MAX_PATH, filename);
+ ok(ret == 4, "Expected 4, got %d\n", ret);
+ ok(!lstrcmpA(buf, "\xe9\x85\x92\x2e"),
+ "Expected \"\xe9\x85\x92\x2e\", got \"%s\"\n", buf);
+
+ memset(buf, 0xc,sizeof(buf));
+ lstrcpyA(buf, "kumquat");
+ ret = GetPrivateProfileStringA("\xe6\xae\xb5\x31", "\xe5\xa7\x93", "default",
+ buf, MAX_PATH, filename);
+ ok(ret == 4, "Expected 4, got %d\n", ret);
+ ok(!lstrcmpA(buf, "\xe6\x9b\xbe\x2e"),
+ "Expected \"\xe6\x9b\xbe\x2e\", got \"%s\"\n", buf);
+
+ memset(buf, 0xc, sizeof(buf));
+ lstrcpyA(buf, "kumquat");
+ ret = GetPrivateProfileStringA("\xe6\xae\xb5\x31", "name6", "default",
+ buf, MAX_PATH, filename);
+ ok(ret == 7, "Expected 7, got %d\n", ret);
+ ok(!lstrcmpA(buf, "\xd7\x99\xd7\x99\xd7\x9f\x2e"),
+ "Expected \"\xd7\x99\xd7\x99\xd7\x9f\x2e\", got \"%s\"\n", buf);
+
+
+ memset(bufW, 0xc, sizeof(bufW));
+ ret = GetPrivateProfileStringW(section_schineseW, name5W, defaultW,
+ bufW, MAX_PATH, filenameW);
+ switch (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())))
+ {
+ case LANG_CHINESE:
+ case LANG_HEBREW:
+ case LANG_JAPANESE:
+ trace("on Chinese, Hebrew or Japanese system.\n");
+ lstrcpyW(expected_valW, defaultW);
+ len = lstrlenW(expected_valW);
+ ok(ret == len, "Expected %d, got %d\n", len, ret);
+ ok(!lstrcmpW(bufW, expected_valW), "Expected \"%s\", got \"%s\"\n",
+ wine_dbgstr_w(expected_valW), wine_dbgstr_w(bufW));
+ break;
+ case LANG_ENGLISH:
+ case LANG_FRENCH:
+ trace("on English or French system.\n");
+ lstrcpyW(expected_valW, expected_val_enW);
+ len = lstrlenW(expected_valW);
+ ok(ret == len, "Expected %d, got %d\n", len, ret);
+ ok(!lstrcmpW(bufW, expected_valW), "Expected \"%s\", got \"%s\"\n",
+ wine_dbgstr_w(expected_valW), wine_dbgstr_w(bufW));
+ break;
+ default:
+ skip("Unknown system language.\n");
+ }
+
/* lpAppName is NULL, not enough room for final section name */
memset(buf, 0xc,sizeof(buf));
lstrcpyA(buf, "kumquat");
@@ -1171,6 +1229,31 @@ static void test_WritePrivateProfileString(void)
"key1=string1" /* 14 bytes */
, 59)), "File doesn't match\n");
DeleteFileA(path);
+
+ data = "[section1]\r\n"
+ "name=\xe9\x85\x92\x2e\r\n";
+ GetTempFileNameA(temp, "wine", 0, path);
+ ret = WritePrivateProfileStringA("section1", "name", "\xe9\x85\x92\x2e", path);
+ ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+ ok(check_file_data(path, data), "File doesn't match\n");
+
+ data = "[section1]\r\n"
+ "name=\xe9\x85\x92\x2e\r\n"
+ "\xe5\xa7\x93=\xe6\x9b\xbe\x2e\r\n";
+ ret = WritePrivateProfileStringA("section1", "\xe5\xa7\x93", "\xe6\x9b\xbe\x2e", path);
+ ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+ ok(check_file_data(path, data), "File doesn't match\n");
+
+ data = "[section1]\r\n"
+ "name=\xe9\x85\x92\x2e\r\n"
+ "\xe5\xa7\x93=\xe6\x9b\xbe\x2e\r\n"
+ "[\xe6\xae\xb5\x31]\r\n"
+ "name2=\xe6\x9b\xbe\x2e\r\n";
+ ret = WritePrivateProfileStringA("\xe6\xae\xb5\x31", "name2", "\xe6\x9b\xbe\x2e", path);
+ ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+ ok(check_file_data(path, data), "File doesn't match\n");
+
+ DeleteFileA(path);
}
START_TEST(profile)
@@ -1189,7 +1272,11 @@ START_TEST(profile)
"name2=\"val2\"\r\n"
"name3\r\n"
"name4=a\r\n"
- "[section2]\r\n",
+ "[section2]\r\n"
+ "[\xe6\xae\xb5\x31]\r\n" /* Simplified Chinese in UTF-8 */
+ "name5=\xe9\x85\x92\x2e\r\n" /* Simplified Chinese in UTF-8 */
+ "\xe5\xa7\x93=\xe6\x9b\xbe\x2e\r\n" /* Simplified Chinese in UTF-8 */
+ "name6=\xd7\x99\xd7\x99\xd7\x9f\x2e\r\n", /* Hebrew in UTF-8 */
"CR+LF");
test_GetPrivateProfileString(
"[section1]\r"
@@ -1197,7 +1284,11 @@ START_TEST(profile)
"name2=\"val2\"\r"
"name3\r"
"name4=a\r"
- "[section2]\r",
+ "[section2]\r"
+ "[\xe6\xae\xb5\x31]\r" /* Simplified Chinese in UTF-8 */
+ "name5=\xe9\x85\x92\x2e\r" /* Simplified Chinese in UTF-8 */
+ "\xe5\xa7\x93=\xe6\x9b\xbe\x2e\r" /* Simplified Chinese in UTF-8 */
+ "name6=\xd7\x99\xd7\x99\xd7\x9f\x2e\r", /* Hebrew in UTF-8 */
"CR only");
test_WritePrivateProfileString();
}
--
2.20.1
April 30, 2019