cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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