[PATCH v2 3/4] kernelbase: Implement SetEnvironmentStrings().

Zebediah Figura z.figura12 at gmail.com
Wed May 6 09:40:28 CDT 2020


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48308
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
v2: Link dynamically to avoid test failures.

 ...ms-win-core-processenvironment-l1-1-0.spec |  2 +-
 ...ms-win-core-processenvironment-l1-2-0.spec |  2 +-
 dlls/kernel32/kernel32.spec                   |  4 +-
 dlls/kernel32/tests/environ.c                 | 86 +++++++++++++++++++
 dlls/kernelbase/kernelbase.spec               |  3 +-
 dlls/kernelbase/process.c                     | 66 ++++++++++++++
 include/winbase.h                             |  3 +
 7 files changed, 161 insertions(+), 5 deletions(-)

diff --git a/dlls/api-ms-win-core-processenvironment-l1-1-0/api-ms-win-core-processenvironment-l1-1-0.spec b/dlls/api-ms-win-core-processenvironment-l1-1-0/api-ms-win-core-processenvironment-l1-1-0.spec
index e3698d6efd1..b39f8bce57a 100644
--- a/dlls/api-ms-win-core-processenvironment-l1-1-0/api-ms-win-core-processenvironment-l1-1-0.spec
+++ b/dlls/api-ms-win-core-processenvironment-l1-1-0/api-ms-win-core-processenvironment-l1-1-0.spec
@@ -15,7 +15,7 @@
 @ stdcall SearchPathW(wstr wstr wstr long ptr ptr) kernel32.SearchPathW
 @ stdcall SetCurrentDirectoryA(str) kernel32.SetCurrentDirectoryA
 @ stdcall SetCurrentDirectoryW(wstr) kernel32.SetCurrentDirectoryW
-@ stub SetEnvironmentStringsW
+@ stdcall SetEnvironmentStringsW(wstr) kernel32.SetEnvironmentStringsW
 @ stdcall SetEnvironmentVariableA(str str) kernel32.SetEnvironmentVariableA
 @ stdcall SetEnvironmentVariableW(wstr wstr) kernel32.SetEnvironmentVariableW
 @ stdcall SetStdHandle(long long) kernel32.SetStdHandle
diff --git a/dlls/api-ms-win-core-processenvironment-l1-2-0/api-ms-win-core-processenvironment-l1-2-0.spec b/dlls/api-ms-win-core-processenvironment-l1-2-0/api-ms-win-core-processenvironment-l1-2-0.spec
index 2c25ee1a076..5638fdb7b13 100644
--- a/dlls/api-ms-win-core-processenvironment-l1-2-0/api-ms-win-core-processenvironment-l1-2-0.spec
+++ b/dlls/api-ms-win-core-processenvironment-l1-2-0/api-ms-win-core-processenvironment-l1-2-0.spec
@@ -17,7 +17,7 @@
 @ stdcall SearchPathW(wstr wstr wstr long ptr ptr) kernel32.SearchPathW
 @ stdcall SetCurrentDirectoryA(str) kernel32.SetCurrentDirectoryA
 @ stdcall SetCurrentDirectoryW(wstr) kernel32.SetCurrentDirectoryW
-@ stub SetEnvironmentStringsW
+@ stdcall SetEnvironmentStringsW(wstr) kernel32.SetEnvironmentStringsW
 @ stdcall SetEnvironmentVariableA(str str) kernel32.SetEnvironmentVariableA
 @ stdcall SetEnvironmentVariableW(wstr wstr) kernel32.SetEnvironmentVariableW
 @ stdcall SetStdHandle(long long) kernel32.SetStdHandle
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 0dd3813987a..fdd0917f444 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -1388,8 +1388,8 @@
 @ stdcall SetDllDirectoryW(wstr)
 # @ stub SetDynamicTimeZoneInformation
 @ stdcall -import SetEndOfFile(long)
-# @ stub SetEnvironmentStringsA
-# @ stub SetEnvironmentStringsW
+@ stdcall -import SetEnvironmentStringsA(str)
+@ stdcall -import SetEnvironmentStringsW(wstr)
 @ stdcall -import SetEnvironmentVariableA(str str)
 @ stdcall -import SetEnvironmentVariableW(wstr wstr)
 @ stdcall -import SetErrorMode(long)
diff --git a/dlls/kernel32/tests/environ.c b/dlls/kernel32/tests/environ.c
index 128a5fdbe52..26f24caad2b 100644
--- a/dlls/kernel32/tests/environ.c
+++ b/dlls/kernel32/tests/environ.c
@@ -36,6 +36,7 @@ static BOOL (WINAPI *pGetComputerNameExA)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD);
 static BOOL (WINAPI *pGetComputerNameExW)(COMPUTER_NAME_FORMAT,LPWSTR,LPDWORD);
 static BOOL (WINAPI *pOpenProcessToken)(HANDLE,DWORD,PHANDLE);
 static BOOL (WINAPI *pGetUserProfileDirectoryA)(HANDLE,LPSTR,LPDWORD);
+static BOOL (WINAPI *pSetEnvironmentStringsW)(WCHAR *);
 
 static void init_functionpointers(void)
 {
@@ -45,6 +46,7 @@ static void init_functionpointers(void)
 
     pGetComputerNameExA = (void *)GetProcAddress(hkernel32, "GetComputerNameExA");
     pGetComputerNameExW = (void *)GetProcAddress(hkernel32, "GetComputerNameExW");
+    pSetEnvironmentStringsW = (void *)GetProcAddress(hkernel32, "SetEnvironmentStringsW");
     pOpenProcessToken = (void *)GetProcAddress(hadvapi32, "OpenProcessToken");
     pGetUserProfileDirectoryA = (void *)GetProcAddress(huserenv,
                                                        "GetUserProfileDirectoryA");
@@ -602,6 +604,89 @@ static void test_GetEnvironmentStringsW(void)
     FreeEnvironmentStringsW(env2);
 }
 
+#define copy_string(dst, src) memcpy(dst, src, sizeof(src))
+
+static void check_env_var_(int line, const char *var, const char *value)
+{
+    char buffer[20];
+    DWORD size = GetEnvironmentVariableA(var, buffer, sizeof(buffer));
+    if (value)
+    {
+        ok_(__FILE__, line)(size == strlen(value), "wrong size %u\n", size);
+        ok_(__FILE__, line)(!strcmp(buffer, value), "wrong value %s\n", debugstr_a(buffer));
+    }
+    else
+    {
+        ok_(__FILE__, line)(!size, "wrong size %u\n", size);
+        ok_(__FILE__, line)(GetLastError() == ERROR_ENVVAR_NOT_FOUND, "got error %u\n", GetLastError());
+    }
+}
+#define check_env_var(a, b) check_env_var_(__LINE__, a, b)
+
+static void test_SetEnvironmentStrings(void)
+{
+    static const WCHAR testenv[] = L"testenv1=unus\0testenv3=tres\0";
+    WCHAR env[200];
+    WCHAR *old_env;
+    BOOL ret;
+
+    if (!pSetEnvironmentStringsW)
+    {
+        win_skip("SetEnvironmentStringsW() is not available\n");
+        return;
+    }
+
+    ret = SetEnvironmentVariableA("testenv1", "heis");
+    ok(ret, "got error %u\n", GetLastError());
+    ret = SetEnvironmentVariableA("testenv2", "dyo");
+    ok(ret, "got error %u\n", GetLastError());
+
+    old_env = GetEnvironmentStringsW();
+
+    memcpy(env, testenv, sizeof(testenv));
+    ret = pSetEnvironmentStringsW(env);
+    ok(ret, "got error %u\n", GetLastError());
+    ok(!memcmp(env, testenv, sizeof(testenv)), "input parameter should not be changed\n");
+
+    check_env_var("testenv1", "unus");
+    check_env_var("testenv2", NULL);
+    check_env_var("testenv3", "tres");
+    check_env_var("PATH", NULL);
+
+    ret = pSetEnvironmentStringsW(old_env);
+    ok(ret, "got error %u\n", GetLastError());
+
+    check_env_var("testenv1", "heis");
+    check_env_var("testenv2", "dyo");
+    check_env_var("testenv3", NULL);
+
+    SetEnvironmentVariableA("testenv1", NULL);
+    SetEnvironmentVariableA("testenv2", NULL);
+
+    copy_string(env, L"testenv\0");
+    SetLastError(0xdeadbeef);
+    ret = pSetEnvironmentStringsW(env);
+    ok(!ret, "expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError());
+
+    copy_string(env, L"=unus\0");
+    SetLastError(0xdeadbeef);
+    ret = pSetEnvironmentStringsW(env);
+    ok(!ret, "expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError());
+
+    copy_string(env, L"one=two=three four=five\0");
+    ret = pSetEnvironmentStringsW(env);
+    ok(ret, "got error %u\n", GetLastError());
+
+    check_env_var("one", "two=three four=five");
+
+    ret = pSetEnvironmentStringsW(old_env);
+    ok(ret, "got error %u\n", GetLastError());
+    ret = FreeEnvironmentStringsW(old_env);
+    ok(ret, "got error %u\n", GetLastError());
+}
+
 START_TEST(environ)
 {
     init_functionpointers();
@@ -614,4 +699,5 @@ START_TEST(environ)
     test_GetComputerNameExA();
     test_GetComputerNameExW();
     test_GetEnvironmentStringsW();
+    test_SetEnvironmentStrings();
 }
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index e73682af0f4..d50d50c2b55 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1422,7 +1422,8 @@
 @ stdcall SetDefaultDllDirectories(long)
 # @ stub SetDynamicTimeZoneInformation
 @ stdcall SetEndOfFile(long)
-@ stub SetEnvironmentStringsW
+@ stdcall SetEnvironmentStringsA(str)
+@ stdcall SetEnvironmentStringsW(wstr)
 @ stdcall SetEnvironmentVariableA(str str)
 @ stdcall SetEnvironmentVariableW(wstr wstr)
 @ stdcall SetErrorMode(long)
diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c
index acef2c55a17..c426978114f 100644
--- a/dlls/kernelbase/process.c
+++ b/dlls/kernelbase/process.c
@@ -1274,6 +1274,72 @@ LPWSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsW(void)
 }
 
 
+/***********************************************************************
+ *           SetEnvironmentStringsA   (kernelbase.@)
+ */
+BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentStringsA( char *env )
+{
+    WCHAR *envW;
+    const char *p = env;
+    DWORD len;
+    BOOL ret;
+
+    for (p = env; *p; p += strlen( p ) + 1);
+
+    len = MultiByteToWideChar( CP_ACP, 0, env, p - env, NULL, 0 );
+    if (!(envW = HeapAlloc( GetProcessHeap(), 0, len )))
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        return FALSE;
+    }
+    MultiByteToWideChar( CP_ACP, 0, env, p - env, envW, len );
+    ret = SetEnvironmentStringsW( envW );
+    HeapFree( GetProcessHeap(), 0, envW );
+    return ret;
+}
+
+
+/***********************************************************************
+ *           SetEnvironmentStringsW   (kernelbase.@)
+ */
+BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentStringsW( WCHAR *env )
+{
+    WCHAR *p;
+    WCHAR *new_env;
+    NTSTATUS status;
+
+    for (p = env; *p; p += wcslen( p ) + 1)
+    {
+        const WCHAR *eq = wcschr( p, '=' );
+        if (!eq || eq == p)
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return FALSE;
+        }
+    }
+
+    if ((status = RtlCreateEnvironment( FALSE, &new_env )))
+        return set_ntstatus( status );
+
+    for (p = env; *p; p += wcslen( p ) + 1)
+    {
+        const WCHAR *eq = wcschr( p, '=' );
+        UNICODE_STRING var, value;
+        var.Buffer = p;
+        var.Length = (eq - p) * sizeof(WCHAR);
+        RtlInitUnicodeString( &value, eq + 1 );
+        if ((status = RtlSetEnvironmentVariable( &new_env, &var, &value )))
+        {
+            RtlDestroyEnvironment( new_env );
+            return set_ntstatus( status );
+        }
+    }
+
+    RtlSetCurrentEnvironment( new_env, NULL );
+    return TRUE;
+}
+
+
 /***********************************************************************
  *           GetEnvironmentVariableA   (kernelbase.@)
  */
diff --git a/include/winbase.h b/include/winbase.h
index f92d864c781..78ed660cc72 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -2619,6 +2619,9 @@ WINBASEAPI BOOL        WINAPI SetDllDirectoryA(LPCSTR);
 WINBASEAPI BOOL        WINAPI SetDllDirectoryW(LPCWSTR);
 #define                       SetDllDirectory WINELIB_NAME_AW(SetDllDirectory)
 WINBASEAPI BOOL        WINAPI SetEndOfFile(HANDLE);
+WINBASEAPI BOOL        WINAPI SetEnvironmentStringsA(char *);
+WINBASEAPI BOOL        WINAPI SetEnvironmentStringsW(WCHAR *);
+#define                       SetEnvironmentStrings WINELIB_NAME_AW(SetEnvironmentStrings)
 WINBASEAPI BOOL        WINAPI SetEnvironmentVariableA(LPCSTR,LPCSTR);
 WINBASEAPI BOOL        WINAPI SetEnvironmentVariableW(LPCWSTR,LPCWSTR);
 #define                       SetEnvironmentVariable WINELIB_NAME_AW(SetEnvironmentVariable)
-- 
2.26.2




More information about the wine-devel mailing list