[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