mirror of https://github.com/encounter/SDL.git
285 lines
6.5 KiB
C
285 lines
6.5 KiB
C
|
/* 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
|