In Windows, when invoked with filename = NULL, these functions:
WritePrivateProfileStringW, WritePrivateProfileSectionW, GetPrivateProfileSectionNamesW, GetPrivateProfileStringW
Behave as if filename is "win.ini" If the corresponding map exists in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping then this map gets used.
Since in freshly installed Wine and Windows 10 such a map exists this tests only verifies that behavior. It does not verify actual writting/reading to C:\windows\win.ini.
Signed-off-by: Carlos Rivera carlos@superkaos.org ---
This IniFileMapping does not actually happen in Wine, which at least in the case of GetPrivateProfileStringW just tries to read from C:\windows\win.ini
This explains the failure in Wine of the first test in function test_profile_int (get 70, expected 0), where there is an invokation like this:
GetPrivateProfileIntA(NULL, NULL, 70, NULL)
And which ends up calling GetPrivateProfileStringW which because the first parameters are NULL invoke GetPrivateProfileSectionNamesW. It then gets the section names from win.ini. In wine, the IniFileMapping is ignored and if there is no win.ini file, it returns a 0 and the default value 70 ends up being returned to the user. If one creates a C:\win.ini file with just one section like: [hello]
Then it gets the section name, and when trying to convert it into a integer it gets converted to 0. The test passes. Thanks to zf in #winehackers for the tip that this bug had something to do with the presence of win.ini.
Interestinly enough, if one names the section something like: [42]
Then test fails with a value of 42 instead of the expected 0!
This behavior is the same in Windows except that it uses the entries in IniFileMapping. If the mapping is removed the file is used as in Wine.
My next commit will make Wine to make use of the IniFileMapping too when filename=NULL-->win.ini, as in Windows. --- dlls/kernel32/tests/Makefile.in | 2 +- dlls/kernel32/tests/profile.c | 92 +++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in index e9516603ce..04c44e208a 100644 --- a/dlls/kernel32/tests/Makefile.in +++ b/dlls/kernel32/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = kernel32.dll -IMPORTS = user32 advapi32 +IMPORTS = user32 advapi32 kernelbase
SOURCES = \ actctx.c \ diff --git a/dlls/kernel32/tests/profile.c b/dlls/kernel32/tests/profile.c index f981558548..9d89009e46 100644 --- a/dlls/kernel32/tests/profile.c +++ b/dlls/kernel32/tests/profile.c @@ -25,6 +25,7 @@ #include "windef.h" #include "winbase.h" #include "windows.h" +#include "shlwapi.h" #include "sddl.h"
#define KEY "ProfileInt" @@ -1588,6 +1589,96 @@ static void test_registry_mapping(void) ok(ret, "got error %u\n", GetLastError()); }
+static void test_null_filename(void) +{ + /* Some profile functions assume filename is win.ini if NULL is given + and if such a map exists in IniFileMapping then they use it */ + + HKEY mapping_key, mapped_key; + char buffer[1024]; + char* p; + int found = 0; + LSTATUS ret; + + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + "Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping\win.ini", + 0, KEY_READ | KEY_WRITE, &mapping_key); + + if(ret) + { + skip("Failed to find a win.ini IniFileMapping registry entry\n"); + return; + } + + if (PathFileExistsA("C:/windows/win.ini")) + { + ret = MoveFileA("C:/windows/win.ini", "C:/windows/winini.bak"); + + if (!ret) + { + skip("Failed to move C:/windows/win.ini out of the way to prevent possibly destructive tests.\n"); + return; + } + } + + ret = RegSetValueExA(mapping_key, "section1", 0, REG_SZ, (BYTE *)"USR:section1_map", sizeof("USR:section1_map")); + ok(!ret, "got error %u\n", ret); + ret = WritePrivateProfileStringA(NULL, NULL, NULL, "win.ini"); + todo_wine ok(ret, "got error %u\n", GetLastError()); + + ret = WritePrivateProfileStringA("section1", "name1", "42", NULL); + ok(ret, "got error %u\n", ret); + + ret = DeleteFileA("C:/windows/win.ini"); + ok(!ret, "expected failure\n"); + + ret = RegOpenKeyExA(HKEY_CURRENT_USER, "section1_map", 0, KEY_READ | KEY_WRITE, &mapped_key); + check_registry_value(mapped_key, "name1", "42"); + + check_profile_string("section1", "name1", NULL, "42"); + + memset(buffer, 0xc, sizeof(buffer)); + ret = GetPrivateProfileSectionNamesA(buffer, sizeof(buffer), NULL); + ok(ret, "got error %u\n", ret); + + if (ret) + { + p = buffer; + while (p < (buffer + sizeof(buffer) - 1)) + { + if (!strncmp("section1", p, sizeof(buffer))) + { + found = 1; + break; + } + while (*p++ && p < (buffer + sizeof(buffer) - 1)); + } + } + + ok(found, + "Expected "section1" in buffer, but buffer is %s\n", + debugstr_an(buffer, (ret + 2 >= sizeof(buffer) ? sizeof(buffer) : ret + 1))); + + ret = WritePrivateProfileSectionA("section1", "name2=mango\0", NULL); + ok(ret, "got error %u\n", ret); + + check_registry_value(mapped_key, "name2", "mango"); + + ret = DeleteFileA("C:/windows/win.ini"); + ok(!ret, "expected failure\n"); + + MoveFileA("C:/windows/winini.bak", "C:/windows/win.ini"); + + ret = RegDeleteValueA(mapping_key, "section1"); + ok(!ret, "got error %u\n", ret); + + ret = RegDeleteKeyA(HKEY_CURRENT_USER, "section1_map"); + ok(!ret, "got error %u\n", ret); + + RegCloseKey(mapped_key); + RegCloseKey(mapping_key); +}; + START_TEST(profile) { test_profile_int(); @@ -1617,4 +1708,5 @@ START_TEST(profile) test_WritePrivateProfileString(); test_profile_struct(); test_registry_mapping(); + test_null_filename(); }