| /* See COPYING.txt for the full license governing this code. */ |
| /** |
| * \file windows_process.c |
| * |
| * Source file for the process API on windows. |
| */ |
| |
| |
| #include <SDL.h> |
| #include <SDL_test.h> |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #include "SDL_visualtest_process.h" |
| |
| #if defined(__WIN32__) |
| |
| void |
| LogLastError(char* str) |
| { |
| LPVOID buffer; |
| DWORD dw = GetLastError(); |
| FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM| |
| FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, |
| MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buffer, |
| 0, NULL); |
| SDLTest_LogError("%s: %s", str, (char*)buffer); |
| LocalFree(buffer); |
| } |
| |
| int |
| SDL_LaunchProcess(char* file, char* args, SDL_ProcessInfo* pinfo) |
| { |
| BOOL success; |
| char* working_directory; |
| char* command_line; |
| int path_length, args_length; |
| STARTUPINFO sui = {0}; |
| sui.cb = sizeof(sui); |
| |
| if(!file) |
| { |
| SDLTest_LogError("Path to executable to launched cannot be NULL."); |
| return 0; |
| } |
| if(!pinfo) |
| { |
| SDLTest_LogError("pinfo cannot be NULL."); |
| return 0; |
| } |
| |
| /* get the working directory of the process being launched, so that |
| the process can load any resources it has in it's working directory */ |
| path_length = SDL_strlen(file); |
| if(path_length == 0) |
| { |
| SDLTest_LogError("Length of the file parameter is zero."); |
| return 0; |
| } |
| |
| working_directory = (char*)SDL_malloc(path_length + 1); |
| if(!working_directory) |
| { |
| SDLTest_LogError("Could not allocate working_directory - malloc() failed."); |
| return 0; |
| } |
| |
| SDL_memcpy(working_directory, file, path_length + 1); |
| PathRemoveFileSpec(working_directory); |
| if(SDL_strlen(working_directory) == 0) |
| { |
| SDL_free(working_directory); |
| working_directory = NULL; |
| } |
| |
| /* join the file path and the args string together */ |
| if(!args) |
| args = ""; |
| args_length = SDL_strlen(args); |
| command_line = (char*)SDL_malloc(path_length + args_length + 2); |
| if(!command_line) |
| { |
| SDLTest_LogError("Could not allocate command_line - malloc() failed."); |
| return 0; |
| } |
| SDL_memcpy(command_line, file, path_length); |
| command_line[path_length] = ' '; |
| SDL_memcpy(command_line + path_length + 1, args, args_length + 1); |
| |
| /* create the process */ |
| success = CreateProcess(NULL, command_line, NULL, NULL, FALSE, |
| NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, |
| NULL, working_directory, &sui, &pinfo->pi); |
| if(working_directory) |
| { |
| SDL_free(working_directory); |
| working_directory = NULL; |
| } |
| SDL_free(command_line); |
| if(!success) |
| { |
| LogLastError("CreateProcess() failed"); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| int |
| SDL_GetProcessExitStatus(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps) |
| { |
| DWORD exit_status; |
| BOOL success; |
| |
| if(!pinfo) |
| { |
| SDLTest_LogError("pinfo cannot be NULL"); |
| return 0; |
| } |
| if(!ps) |
| { |
| SDLTest_LogError("ps cannot be NULL"); |
| return 0; |
| } |
| |
| /* get the exit code */ |
| success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status); |
| if(!success) |
| { |
| LogLastError("GetExitCodeProcess() failed"); |
| return 0; |
| } |
| |
| if(exit_status == STILL_ACTIVE) |
| ps->exit_status = -1; |
| else |
| ps->exit_status = exit_status; |
| ps->exit_success = 1; |
| return 1; |
| } |
| |
| |
| int |
| SDL_IsProcessRunning(SDL_ProcessInfo* pinfo) |
| { |
| DWORD exit_status; |
| BOOL success; |
| |
| if(!pinfo) |
| { |
| SDLTest_LogError("pinfo cannot be NULL"); |
| return -1; |
| } |
| |
| success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status); |
| if(!success) |
| { |
| LogLastError("GetExitCodeProcess() failed"); |
| return -1; |
| } |
| |
| if(exit_status == STILL_ACTIVE) |
| return 1; |
| return 0; |
| } |
| |
| static BOOL CALLBACK |
| CloseWindowCallback(HWND hwnd, LPARAM lparam) |
| { |
| DWORD pid; |
| SDL_ProcessInfo* pinfo; |
| |
| pinfo = (SDL_ProcessInfo*)lparam; |
| |
| GetWindowThreadProcessId(hwnd, &pid); |
| if(pid == pinfo->pi.dwProcessId) |
| { |
| DWORD result; |
| if(!SendMessageTimeout(hwnd, WM_CLOSE, 0, 0, SMTO_BLOCK, |
| 1000, &result)) |
| { |
| if(GetLastError() != ERROR_TIMEOUT) |
| { |
| LogLastError("SendMessageTimeout() failed"); |
| return FALSE; |
| } |
| } |
| } |
| return TRUE; |
| } |
| |
| int |
| SDL_QuitProcess(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps) |
| { |
| DWORD wait_result; |
| if(!pinfo) |
| { |
| SDLTest_LogError("pinfo argument cannot be NULL"); |
| return 0; |
| } |
| if(!ps) |
| { |
| SDLTest_LogError("ps argument cannot be NULL"); |
| return 0; |
| } |
| |
| /* enumerate through all the windows, trying to close each one */ |
| if(!EnumWindows(CloseWindowCallback, (LPARAM)pinfo)) |
| { |
| SDLTest_LogError("EnumWindows() failed"); |
| return 0; |
| } |
| |
| /* wait until the process terminates */ |
| wait_result = WaitForSingleObject(pinfo->pi.hProcess, 1000); |
| if(wait_result == WAIT_FAILED) |
| { |
| LogLastError("WaitForSingleObject() failed"); |
| return 0; |
| } |
| if(wait_result != WAIT_OBJECT_0) |
| { |
| SDLTest_LogError("Process did not quit."); |
| return 0; |
| } |
| |
| /* get the exit code */ |
| if(!SDL_GetProcessExitStatus(pinfo, ps)) |
| { |
| SDLTest_LogError("SDL_GetProcessExitStatus() failed"); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| int |
| SDL_KillProcess(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps) |
| { |
| BOOL success; |
| DWORD exit_status, wait_result; |
| |
| if(!pinfo) |
| { |
| SDLTest_LogError("pinfo argument cannot be NULL"); |
| return 0; |
| } |
| if(!ps) |
| { |
| SDLTest_LogError("ps argument cannot be NULL"); |
| return 0; |
| } |
| |
| /* initiate termination of the process */ |
| success = TerminateProcess(pinfo->pi.hProcess, 0); |
| if(!success) |
| { |
| LogLastError("TerminateProcess() failed"); |
| return 0; |
| } |
| |
| /* wait until the process terminates */ |
| wait_result = WaitForSingleObject(pinfo->pi.hProcess, INFINITE); |
| if(wait_result == WAIT_FAILED) |
| { |
| LogLastError("WaitForSingleObject() failed"); |
| return 0; |
| } |
| |
| /* get the exit code */ |
| success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status); |
| if(!success) |
| { |
| LogLastError("GetExitCodeProcess() failed"); |
| return 0; |
| } |
| |
| ps->exit_status = exit_status; |
| ps->exit_success = 1; |
| |
| return 1; |
| } |
| |
| #endif |