Edit

kc3-lang/SDL/visualtest/src/windows/windows_process.c

Branch :

  • Show log

    Commit

  • Author : Ryan C. Gordon
    Date : 2021-02-18 11:06:44
    Hash : abe2c0f1
    Message : license: Fixed references to COPYING.txt that are now LICENSE.txt. Fixes #4108

  • visualtest/src/windows/windows_process.c
  • /* See LICENSE.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