libwinpr-environment: implement required functions for CreateProcess
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Mon, 23 Sep 2013 18:44:59 +0000 (14:44 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Mon, 23 Sep 2013 18:44:59 +0000 (14:44 -0400)
14 files changed:
winpr/include/winpr/environment.h
winpr/include/winpr/thread.h
winpr/include/winpr/wtypes.h
winpr/libwinpr/environment/CMakeLists.txt
winpr/libwinpr/environment/environment.c
winpr/libwinpr/environment/test/.gitignore [new file with mode: 0644]
winpr/libwinpr/environment/test/CMakeLists.txt [new file with mode: 0644]
winpr/libwinpr/environment/test/TestEnvironmentGetEnvironmentStrings.c [new file with mode: 0644]
winpr/libwinpr/environment/test/TestEnvironmentSetEnvironmentVariable.c [new file with mode: 0644]
winpr/libwinpr/synch/wait.c
winpr/libwinpr/thread/process.c
winpr/libwinpr/thread/test/CMakeLists.txt
winpr/libwinpr/thread/test/TestThreadCreateProcess.c
winpr/libwinpr/thread/thread.h

index b77ab71..0df30f5 100644 (file)
@@ -54,6 +54,11 @@ WINPR_API DWORD GetEnvironmentVariableW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD n
 WINPR_API BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue);
 WINPR_API BOOL SetEnvironmentVariableW(LPCWSTR lpName, LPCWSTR lpValue);
 
+/**
+ * A brief history of the GetEnvironmentStrings functions:
+ * http://blogs.msdn.com/b/oldnewthing/archive/2013/01/17/10385718.aspx
+ */
+
 WINPR_API LPCH GetEnvironmentStrings(VOID);
 WINPR_API LPWCH GetEnvironmentStringsW(VOID);
 
@@ -79,6 +84,7 @@ WINPR_API BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock);
 #define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathW
 #define GetEnvironmentVariable         GetEnvironmentVariableW
 #define SetEnvironmentVariable         SetEnvironmentVariableW
+#define GetEnvironmentStrings          GetEnvironmentStringsW
 #define SetEnvironmentStrings          SetEnvironmentStringsW
 #define ExpandEnvironmentStrings       ExpandEnvironmentStringsW
 #define FreeEnvironmentStrings         FreeEnvironmentStringsW
@@ -90,6 +96,7 @@ WINPR_API BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock);
 #define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathA
 #define GetEnvironmentVariable         GetEnvironmentVariableA
 #define SetEnvironmentVariable         SetEnvironmentVariableA
+#define GetEnvironmentStringsA         GetEnvironmentStrings
 #define SetEnvironmentStrings          SetEnvironmentStringsA
 #define ExpandEnvironmentStrings       ExpandEnvironmentStringsA
 #define FreeEnvironmentStrings         FreeEnvironmentStringsA
index 9114a67..6d2444d 100644 (file)
@@ -111,6 +111,7 @@ WINPR_API BOOL CreateProcessAsUserW(HANDLE hToken, LPCWSTR lpApplicationName, LP
 #endif
 
 DECLSPEC_NORETURN WINPR_API VOID ExitProcess(UINT uExitCode);
+WINPR_API BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode);
 
 WINPR_API HANDLE _GetCurrentProcess(void);
 WINPR_API DWORD GetCurrentProcessId(void);
index d3639d7..034c7e6 100644 (file)
@@ -108,10 +108,10 @@ typedef signed int LONG32;
 typedef signed __int64 LONG64;
 #endif
 
-typedef CHARPSTR, *LPSTR, *LPCH;
+typedef CHAR *PSTR, *LPSTR, *LPCH;
 typedef const CHAR *LPCSTR,*PCSTR;
 
-typedef WCHARLPWSTR, *PWSTR, *LPWCH;
+typedef WCHAR *LPWSTR, *PWSTR, *LPWCH;
 typedef const WCHAR *LPCWSTR,*PCWSTR;
 
 typedef unsigned __int64 QWORD;
index 831fa78..6f5ab2c 100644 (file)
@@ -38,3 +38,7 @@ else()
 endif()
 
 set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")
+
+if(BUILD_TESTING)
+       add_subdirectory(test)
+endif()
index 058232d..f1bcf56 100644 (file)
@@ -157,6 +157,25 @@ DWORD GetEnvironmentVariableW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize)
 
 BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue)
 {
+       int length;
+       char* envstr;
+
+       if (!lpName)
+               return FALSE;
+
+       if (lpValue)
+       {
+               length = strlen(lpName) + strlen(lpValue) + 1;
+               envstr = (char*) malloc(length + 1);
+               sprintf_s(envstr, length + 1, "%s=%s", lpName, lpValue);
+               envstr[length] = '\0';
+               putenv(envstr);
+       }
+       else
+       {
+               unsetenv(lpName);
+       }
+
        return TRUE;
 }
 
@@ -165,9 +184,61 @@ BOOL SetEnvironmentVariableW(LPCWSTR lpName, LPCWSTR lpValue)
        return TRUE;
 }
 
+/**
+ * GetEnvironmentStrings function:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/ms683187/
+ *
+ * The GetEnvironmentStrings function returns a pointer to a block of memory
+ * that contains the environment variables of the calling process (both the
+ * system and the user environment variables). Each environment block contains
+ * the environment variables in the following format:
+ *
+ * Var1=Value1\0
+ * Var2=Value2\0
+ * Var3=Value3\0
+ * ...
+ * VarN=ValueN\0\0
+ */
+
+extern char** environ;
+
 LPCH GetEnvironmentStrings(VOID)
 {
-       return NULL;
+       char* p;
+       int offset;
+       int length;
+       char** envp;
+       DWORD cchEnvironmentBlock;
+       LPCH lpszEnvironmentBlock;
+
+       offset = 0;
+       envp = environ;
+
+       cchEnvironmentBlock = 128;
+       lpszEnvironmentBlock = (LPCH) malloc(cchEnvironmentBlock * sizeof(CHAR));
+
+       while (*envp)
+       {
+               length = strlen(*envp);
+
+               while ((offset + length + 8) > cchEnvironmentBlock)
+               {
+                       cchEnvironmentBlock *= 2;
+                       lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
+               }
+
+               p = &(lpszEnvironmentBlock[offset]);
+
+               CopyMemory(p, *envp, length * sizeof(CHAR));
+               p[length] = '\0';
+
+               offset += (length + 1);
+               envp++;
+       }
+
+       lpszEnvironmentBlock[offset] = '\0';
+
+       return lpszEnvironmentBlock;
 }
 
 LPWCH GetEnvironmentStringsW(VOID)
@@ -197,6 +268,9 @@ DWORD ExpandEnvironmentStringsW(LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize)
 
 BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock)
 {
+       if (lpszEnvironmentBlock)
+               free(lpszEnvironmentBlock);
+
        return TRUE;
 }
 
diff --git a/winpr/libwinpr/environment/test/.gitignore b/winpr/libwinpr/environment/test/.gitignore
new file mode 100644 (file)
index 0000000..4792140
--- /dev/null
@@ -0,0 +1,3 @@
+TestEnvironment
+TestEnvironment.c
+
diff --git a/winpr/libwinpr/environment/test/CMakeLists.txt b/winpr/libwinpr/environment/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5b9ec3f
--- /dev/null
@@ -0,0 +1,31 @@
+
+set(MODULE_NAME "TestEnvironment")
+set(MODULE_PREFIX "TEST_ENVIRONMENT")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+       TestEnvironmentGetEnvironmentStrings.c
+       TestEnvironmentSetEnvironmentVariable.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+       ${${MODULE_PREFIX}_DRIVER}
+       ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+       MONOLITHIC ${MONOLITHIC_BUILD}
+       MODULE winpr
+       MODULES winpr-environment)
+
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+       get_filename_component(TestName ${test} NAME_WE)
+       add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
diff --git a/winpr/libwinpr/environment/test/TestEnvironmentGetEnvironmentStrings.c b/winpr/libwinpr/environment/test/TestEnvironmentGetEnvironmentStrings.c
new file mode 100644 (file)
index 0000000..0aa0435
--- /dev/null
@@ -0,0 +1,28 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/environment.h>
+
+int TestEnvironmentGetEnvironmentStrings(int argc, char* argv[])
+{
+       TCHAR* p;
+       int length;
+       LPTCH lpszEnvironmentBlock;
+
+       lpszEnvironmentBlock = GetEnvironmentStrings();
+
+       p = (TCHAR*) lpszEnvironmentBlock;
+
+       while (p[0] && p[1])
+       {
+               printf("%s\n", p);
+               length = strlen(p);
+               p += (length + 1);
+       }
+
+       FreeEnvironmentStrings(lpszEnvironmentBlock);
+
+       return 0;
+}
+
diff --git a/winpr/libwinpr/environment/test/TestEnvironmentSetEnvironmentVariable.c b/winpr/libwinpr/environment/test/TestEnvironmentSetEnvironmentVariable.c
new file mode 100644 (file)
index 0000000..a80010d
--- /dev/null
@@ -0,0 +1,30 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/environment.h>
+
+int TestEnvironmentSetEnvironmentVariable(int argc, char* argv[])
+{
+       DWORD nSize;
+       LPSTR lpBuffer;
+
+       SetEnvironmentVariableA("WINPR_TEST_VARIABLE", "WINPR_TEST_VALUE");
+
+       nSize = GetEnvironmentVariableA("WINPR_TEST_VARIABLE", NULL, 0);
+
+       lpBuffer = (LPSTR) malloc(nSize);
+       nSize = GetEnvironmentVariableA("WINPR_TEST_VARIABLE", lpBuffer, nSize);
+
+       printf("GetEnvironmentVariableA(WINPR_TEST_VARIABLE) = %s\n" , lpBuffer);
+
+       if (strcmp(lpBuffer, "WINPR_TEST_VALUE") != 0)
+       {
+               return -1;
+       }
+
+       free(lpBuffer);
+
+       return 0;
+}
+
index 8727831..823a07f 100644 (file)
@@ -114,6 +114,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
                {
                        return WAIT_FAILED;
                }
+
+               process->dwExitCode = (DWORD) process->status;
        }
        else if (Type == HANDLE_TYPE_MUTEX)
        {
index 347b2ac..9c9e9c3 100644 (file)
@@ -56,6 +56,8 @@
 #endif
 
 #include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/environment.h>
 
 #include <errno.h>
 #include <spawn.h>
 
 #include "../handle/handle.h"
 
+char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
+{
+       char* p;
+       int index;
+       int count;
+       int length;
+       char** envp = NULL;
+
+       count = 0;
+       p = (char*) lpszEnvironmentBlock;
+
+       while (p[0] && p[1])
+       {
+               length = strlen(p);
+               p += (length + 1);
+               count++;
+       }
+
+       index = 0;
+       p = (char*) lpszEnvironmentBlock;
+
+       envp = (char**) malloc(sizeof(char*) * (count + 1));
+       envp[count] = NULL;
+
+       while (p[0] && p[1])
+       {
+               length = strlen(p);
+               envp[index] = _strdup(p);
+               p += (length + 1);
+               index++;
+       }
+
+       return envp;
+}
+
 BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
                LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment,
                LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
 {
        pid_t pid;
-       char* envp;
        int status;
        int numArgs;
        LPSTR* pArgs;
+       char** envp;
        WINPR_THREAD* thread;
        WINPR_PROCESS* process;
+       LPTCH lpszEnvironmentBlock;
 
        pid = 0;
+       envp = NULL;
        numArgs = 0;
+       lpszEnvironmentBlock = NULL;
 
        pArgs = CommandLineToArgvA(lpCommandLine, &numArgs);
 
-       envp = NULL;
+       if (lpEnvironment)
+       {
+               envp = EnvironmentBlockToEnvpA(lpEnvironment);
+       }
+       else
+       {
+               lpszEnvironmentBlock = GetEnvironmentStrings();
+               envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock);
+       }
 
-       status = posix_spawnp(&pid, pArgs[0], NULL, NULL, pArgs, &envp);
+       status = posix_spawnp(&pid, pArgs[0], NULL, NULL, pArgs, envp);
 
        if (status != 0)
                return FALSE;
@@ -102,6 +150,7 @@ BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_AT
 
        process->pid = pid;
        process->status = 0;
+       process->dwExitCode = 0;
 
        thread = (WINPR_THREAD*) malloc(sizeof(WINPR_THREAD));
 
@@ -148,6 +197,23 @@ DECLSPEC_NORETURN VOID ExitProcess(UINT uExitCode)
 
 }
 
+BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
+{
+       WINPR_PROCESS* process;
+
+       if (!hProcess)
+               return FALSE;
+
+       if (!lpExitCode)
+               return FALSE;
+
+       process = (WINPR_PROCESS*) hProcess;
+
+       *lpExitCode = process->dwExitCode;
+
+       return TRUE;
+}
+
 HANDLE _GetCurrentProcess(VOID)
 {
        return NULL;
index 1f6de6f..9ca3a9a 100644 (file)
@@ -17,7 +17,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
 set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
        MONOLITHIC ${MONOLITHIC_BUILD}
        MODULE winpr
-       MODULES winpr-thread winpr-heap)
+       MODULES winpr-thread winpr-heap winpr-environment)
 
 target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
 
index 889fb5c..b57b0a1 100644 (file)
@@ -4,10 +4,12 @@
 #include <winpr/tchar.h>
 #include <winpr/synch.h>
 #include <winpr/thread.h>
+#include <winpr/environment.h>
 
 int TestThreadCreateProcess(int argc, char* argv[])
 {
        BOOL status;
+       DWORD exitCode;
        LPCTSTR lpApplicationName;
        LPTSTR lpCommandLine;
        LPSECURITY_ATTRIBUTES lpProcessAttributes;
@@ -18,14 +20,19 @@ int TestThreadCreateProcess(int argc, char* argv[])
        LPCTSTR lpCurrentDirectory;
        STARTUPINFO StartupInfo;
        PROCESS_INFORMATION ProcessInformation;
+       LPTCH lpszEnvironmentBlock;
+
+       lpszEnvironmentBlock = GetEnvironmentStrings();
 
        lpApplicationName = NULL;
-       lpCommandLine = _T("ls -l /");
+       //lpCommandLine = _T("ls -l /");
+       lpCommandLine = _T("printenv");
        lpProcessAttributes = NULL;
        lpThreadAttributes = NULL;
        bInheritHandles = FALSE;
        dwCreationFlags = 0;
        lpEnvironment = NULL;
+       lpEnvironment = lpszEnvironmentBlock;
        lpCurrentDirectory = NULL;
        ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
        StartupInfo.cb = sizeof(STARTUPINFO);
@@ -42,8 +49,14 @@ int TestThreadCreateProcess(int argc, char* argv[])
                        &StartupInfo,
                        &ProcessInformation);
 
+       FreeEnvironmentStrings(lpszEnvironmentBlock);
+
        WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
 
+       status = GetExitCodeProcess(ProcessInformation.hProcess, &exitCode);
+
+       printf("Process exited with code: %d\n", exitCode);
+
        CloseHandle(ProcessInformation.hProcess);
        CloseHandle(ProcessInformation.hThread);
 
index 6652ed3..67fc3d8 100644 (file)
@@ -52,6 +52,7 @@ struct winpr_process
 
        pid_t pid;
        int status;
+       DWORD dwExitCode;
 };
 typedef struct winpr_process WINPR_PROCESS;