windows_process.c (6631B)
1/* See COPYING.txt for the full license governing this code. */ 2/** 3 * \file windows_process.c 4 * 5 * Source file for the process API on windows. 6 */ 7 8 9#include <SDL.h> 10#include <SDL_test.h> 11#include <string.h> 12#include <stdlib.h> 13 14#include "SDL_visualtest_process.h" 15 16#if defined(__WIN32__) 17 18void 19LogLastError(char* str) 20{ 21 LPVOID buffer; 22 DWORD dw = GetLastError(); 23 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM| 24 FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, 25 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buffer, 26 0, NULL); 27 SDLTest_LogError("%s: %s", str, (char*)buffer); 28 LocalFree(buffer); 29} 30 31int 32SDL_LaunchProcess(char* file, char* args, SDL_ProcessInfo* pinfo) 33{ 34 BOOL success; 35 char* working_directory; 36 char* command_line; 37 int path_length, args_length; 38 STARTUPINFO sui = {0}; 39 sui.cb = sizeof(sui); 40 41 if(!file) 42 { 43 SDLTest_LogError("Path to executable to launched cannot be NULL."); 44 return 0; 45 } 46 if(!pinfo) 47 { 48 SDLTest_LogError("pinfo cannot be NULL."); 49 return 0; 50 } 51 52 /* get the working directory of the process being launched, so that 53 the process can load any resources it has in it's working directory */ 54 path_length = SDL_strlen(file); 55 if(path_length == 0) 56 { 57 SDLTest_LogError("Length of the file parameter is zero."); 58 return 0; 59 } 60 61 working_directory = (char*)SDL_malloc(path_length + 1); 62 if(!working_directory) 63 { 64 SDLTest_LogError("Could not allocate working_directory - malloc() failed."); 65 return 0; 66 } 67 68 SDL_memcpy(working_directory, file, path_length + 1); 69 PathRemoveFileSpec(working_directory); 70 if(SDL_strlen(working_directory) == 0) 71 { 72 SDL_free(working_directory); 73 working_directory = NULL; 74 } 75 76 /* join the file path and the args string together */ 77 if(!args) 78 args = ""; 79 args_length = SDL_strlen(args); 80 command_line = (char*)SDL_malloc(path_length + args_length + 2); 81 if(!command_line) 82 { 83 SDLTest_LogError("Could not allocate command_line - malloc() failed."); 84 return 0; 85 } 86 SDL_memcpy(command_line, file, path_length); 87 command_line[path_length] = ' '; 88 SDL_memcpy(command_line + path_length + 1, args, args_length + 1); 89 90 /* create the process */ 91 success = CreateProcess(NULL, command_line, NULL, NULL, FALSE, 92 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, 93 NULL, working_directory, &sui, &pinfo->pi); 94 if(working_directory) 95 { 96 SDL_free(working_directory); 97 working_directory = NULL; 98 } 99 SDL_free(command_line); 100 if(!success) 101 { 102 LogLastError("CreateProcess() failed"); 103 return 0; 104 } 105 106 return 1; 107} 108 109int 110SDL_GetProcessExitStatus(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps) 111{ 112 DWORD exit_status; 113 BOOL success; 114 115 if(!pinfo) 116 { 117 SDLTest_LogError("pinfo cannot be NULL"); 118 return 0; 119 } 120 if(!ps) 121 { 122 SDLTest_LogError("ps cannot be NULL"); 123 return 0; 124 } 125 126 /* get the exit code */ 127 success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status); 128 if(!success) 129 { 130 LogLastError("GetExitCodeProcess() failed"); 131 return 0; 132 } 133 134 if(exit_status == STILL_ACTIVE) 135 ps->exit_status = -1; 136 else 137 ps->exit_status = exit_status; 138 ps->exit_success = 1; 139 return 1; 140} 141 142 143int 144SDL_IsProcessRunning(SDL_ProcessInfo* pinfo) 145{ 146 DWORD exit_status; 147 BOOL success; 148 149 if(!pinfo) 150 { 151 SDLTest_LogError("pinfo cannot be NULL"); 152 return -1; 153 } 154 155 success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status); 156 if(!success) 157 { 158 LogLastError("GetExitCodeProcess() failed"); 159 return -1; 160 } 161 162 if(exit_status == STILL_ACTIVE) 163 return 1; 164 return 0; 165} 166 167static BOOL CALLBACK 168CloseWindowCallback(HWND hwnd, LPARAM lparam) 169{ 170 DWORD pid; 171 SDL_ProcessInfo* pinfo; 172 173 pinfo = (SDL_ProcessInfo*)lparam; 174 175 GetWindowThreadProcessId(hwnd, &pid); 176 if(pid == pinfo->pi.dwProcessId) 177 { 178 DWORD result; 179 if(!SendMessageTimeout(hwnd, WM_CLOSE, 0, 0, SMTO_BLOCK, 180 1000, &result)) 181 { 182 if(GetLastError() != ERROR_TIMEOUT) 183 { 184 LogLastError("SendMessageTimeout() failed"); 185 return FALSE; 186 } 187 } 188 } 189 return TRUE; 190} 191 192int 193SDL_QuitProcess(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps) 194{ 195 DWORD wait_result; 196 if(!pinfo) 197 { 198 SDLTest_LogError("pinfo argument cannot be NULL"); 199 return 0; 200 } 201 if(!ps) 202 { 203 SDLTest_LogError("ps argument cannot be NULL"); 204 return 0; 205 } 206 207 /* enumerate through all the windows, trying to close each one */ 208 if(!EnumWindows(CloseWindowCallback, (LPARAM)pinfo)) 209 { 210 SDLTest_LogError("EnumWindows() failed"); 211 return 0; 212 } 213 214 /* wait until the process terminates */ 215 wait_result = WaitForSingleObject(pinfo->pi.hProcess, 1000); 216 if(wait_result == WAIT_FAILED) 217 { 218 LogLastError("WaitForSingleObject() failed"); 219 return 0; 220 } 221 if(wait_result != WAIT_OBJECT_0) 222 { 223 SDLTest_LogError("Process did not quit."); 224 return 0; 225 } 226 227 /* get the exit code */ 228 if(!SDL_GetProcessExitStatus(pinfo, ps)) 229 { 230 SDLTest_LogError("SDL_GetProcessExitStatus() failed"); 231 return 0; 232 } 233 234 return 1; 235} 236 237int 238SDL_KillProcess(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps) 239{ 240 BOOL success; 241 DWORD exit_status, wait_result; 242 243 if(!pinfo) 244 { 245 SDLTest_LogError("pinfo argument cannot be NULL"); 246 return 0; 247 } 248 if(!ps) 249 { 250 SDLTest_LogError("ps argument cannot be NULL"); 251 return 0; 252 } 253 254 /* initiate termination of the process */ 255 success = TerminateProcess(pinfo->pi.hProcess, 0); 256 if(!success) 257 { 258 LogLastError("TerminateProcess() failed"); 259 return 0; 260 } 261 262 /* wait until the process terminates */ 263 wait_result = WaitForSingleObject(pinfo->pi.hProcess, INFINITE); 264 if(wait_result == WAIT_FAILED) 265 { 266 LogLastError("WaitForSingleObject() failed"); 267 return 0; 268 } 269 270 /* get the exit code */ 271 success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status); 272 if(!success) 273 { 274 LogLastError("GetExitCodeProcess() failed"); 275 return 0; 276 } 277 278 ps->exit_status = exit_status; 279 ps->exit_success = 1; 280 281 return 1; 282} 283 284#endif