early-access version 1611

This commit is contained in:
pineappleEA
2021-04-18 05:35:25 +02:00
parent 16f54e367d
commit 18db69f039
1409 changed files with 545335 additions and 10 deletions

View File

@@ -0,0 +1,284 @@
/* 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

View File

@@ -0,0 +1,349 @@
/* See COPYING.txt for the full license governing this code. */
/**
* \file windows_screenshot.c
*
* Source file for the screenshot API on windows.
*/
#include "SDL_visualtest_process.h"
#include <SDL.h>
#include <SDL_test.h>
#if defined(__CYGWIN__)
#include <sys/stat.h>
#endif
#if defined(__WIN32__)
#include <Windows.h>
void LogLastError(char* str);
static int img_num;
static SDL_ProcessInfo screenshot_pinfo;
/* Saves a bitmap to a file using hdc as a device context */
static int
SaveBitmapToFile(HDC hdc, HBITMAP hbitmap, char* filename)
{
BITMAP bitmap;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
DWORD bmpsize, bytes_written;
HANDLE hdib, hfile;
char* bmpdata;
int return_code = 1;
if(!hdc)
{
SDLTest_LogError("hdc argument is NULL");
return 0;
}
if(!hbitmap)
{
SDLTest_LogError("hbitmap argument is NULL");
return 0;
}
if(!filename)
{
SDLTest_LogError("filename argument is NULL");
return 0;
}
if(!GetObject(hbitmap, sizeof(BITMAP), (void*)&bitmap))
{
SDLTest_LogError("GetObject() failed");
return_code = 0;
goto savebitmaptofile_cleanup_generic;
}
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = bitmap.bmWidth;
bih.biHeight = bitmap.bmHeight;
bih.biPlanes = 1;
bih.biBitCount = 32;
bih.biCompression = BI_RGB;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
bmpsize = ((bitmap.bmWidth * bih.biBitCount + 31) / 32) * 4 * bitmap.bmHeight;
hdib = GlobalAlloc(GHND, bmpsize);
if(!hdib)
{
LogLastError("GlobalAlloc() failed");
return_code = 0;
goto savebitmaptofile_cleanup_generic;
}
bmpdata = (char*)GlobalLock(hdib);
if(!bmpdata)
{
LogLastError("GlobalLock() failed");
return_code = 0;
goto savebitmaptofile_cleanup_hdib;
}
if(!GetDIBits(hdc, hbitmap, 0, (UINT)bitmap.bmHeight, bmpdata,
(LPBITMAPINFO)&bih, DIB_RGB_COLORS))
{
SDLTest_LogError("GetDIBits() failed");
return_code = 0;
goto savebitmaptofile_cleanup_unlockhdib;
}
hfile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if(hfile == INVALID_HANDLE_VALUE)
{
LogLastError("CreateFile()");
return_code = 0;
goto savebitmaptofile_cleanup_unlockhdib;
}
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bfh.bfSize = bmpsize + bfh.bfOffBits;
bfh.bfType = 0x4D42;
bytes_written = 0;
if(!WriteFile(hfile, (void*)&bfh, sizeof(BITMAPFILEHEADER), &bytes_written, NULL) ||
!WriteFile(hfile, (void*)&bih, sizeof(BITMAPINFOHEADER), &bytes_written, NULL) ||
!WriteFile(hfile, (void*)bmpdata, bmpsize, &bytes_written, NULL))
{
LogLastError("WriteFile() failed");
return_code = 0;
goto savebitmaptofile_cleanup_hfile;
}
savebitmaptofile_cleanup_hfile:
CloseHandle(hfile);
/* make the screenshot file writable on cygwin, since it could be overwritten later */
#if defined(__CYGWIN__)
if(chmod(filename, 0777) == -1)
{
SDLTest_LogError("chmod() failed");
return_code = 0;
}
#endif
savebitmaptofile_cleanup_unlockhdib:
GlobalUnlock(hdib);
savebitmaptofile_cleanup_hdib:
GlobalFree(hdib);
savebitmaptofile_cleanup_generic:
return return_code;
}
/* Takes the screenshot of a window and saves it to a file. If only_client_area
is true, then only the client area of the window is considered */
static int
ScreenshotWindow(HWND hwnd, char* filename, SDL_bool only_client_area)
{
int width, height;
RECT dimensions;
HDC windowdc, capturedc;
HBITMAP capturebitmap;
HGDIOBJ select_success;
BOOL blt_success;
int return_code = 1;
if(!filename)
{
SDLTest_LogError("filename argument cannot be NULL");
return_code = 0;
goto screenshotwindow_cleanup_generic;
}
if(!hwnd)
{
SDLTest_LogError("hwnd argument cannot be NULL");
return_code = 0;
goto screenshotwindow_cleanup_generic;
}
if(!GetWindowRect(hwnd, &dimensions))
{
LogLastError("GetWindowRect() failed");
return_code = 0;
goto screenshotwindow_cleanup_generic;
}
if(only_client_area)
{
RECT crect;
if(!GetClientRect(hwnd, &crect))
{
SDLTest_LogError("GetClientRect() failed");
return_code = 0;
goto screenshotwindow_cleanup_generic;
}
width = crect.right;
height = crect.bottom;
windowdc = GetDC(hwnd);
if(!windowdc)
{
SDLTest_LogError("GetDC() failed");
return_code = 0;
goto screenshotwindow_cleanup_generic;
}
}
else
{
width = dimensions.right - dimensions.left;
height = dimensions.bottom - dimensions.top;
windowdc = GetWindowDC(hwnd);
if(!windowdc)
{
SDLTest_LogError("GetWindowDC() failed");
return_code = 0;
goto screenshotwindow_cleanup_generic;
}
}
capturedc = CreateCompatibleDC(windowdc);
if(!capturedc)
{
SDLTest_LogError("CreateCompatibleDC() failed");
return_code = 0;
goto screenshotwindow_cleanup_windowdc;
}
capturebitmap = CreateCompatibleBitmap(windowdc, width, height);
if(!capturebitmap)
{
SDLTest_LogError("CreateCompatibleBitmap() failed");
return_code = 0;
goto screenshotwindow_cleanup_capturedc;
}
select_success = SelectObject(capturedc, capturebitmap);
if(!select_success || select_success == HGDI_ERROR)
{
SDLTest_LogError("SelectObject() failed");
return_code = 0;
goto screenshotwindow_cleanup_capturebitmap;
}
blt_success = BitBlt(capturedc, 0, 0, width, height, windowdc,
0, 0, SRCCOPY|CAPTUREBLT);
if(!blt_success)
{
LogLastError("BitBlt() failed");
return_code = 0;
goto screenshotwindow_cleanup_capturebitmap;
}
/* save bitmap as file */
if(!SaveBitmapToFile(windowdc, capturebitmap, filename))
{
SDLTest_LogError("SaveBitmapToFile() failed");
return_code = 0;
goto screenshotwindow_cleanup_capturebitmap;
}
/* free resources */
screenshotwindow_cleanup_capturebitmap:
if(!DeleteObject(capturebitmap))
{
SDLTest_LogError("DeleteObjectFailed");
return_code = 0;
}
screenshotwindow_cleanup_capturedc:
if(!DeleteDC(capturedc))
{
SDLTest_LogError("DeleteDC() failed");
return_code = 0;
}
screenshotwindow_cleanup_windowdc:
if(!ReleaseDC(hwnd, windowdc))
{
SDLTest_LogError("ReleaseDC() failed");
return_code = 0;;
}
screenshotwindow_cleanup_generic:
return return_code;
}
/* Takes the screenshot of the entire desktop and saves it to a file */
int SDLVisualTest_ScreenshotDesktop(char* filename)
{
HWND hwnd;
hwnd = GetDesktopWindow();
return ScreenshotWindow(hwnd, filename, SDL_FALSE);
}
/* take screenshot of a window and save it to a file */
static BOOL CALLBACK
ScreenshotHwnd(HWND hwnd, LPARAM lparam)
{
int len;
DWORD pid;
char* prefix;
char* filename;
GetWindowThreadProcessId(hwnd, &pid);
if(pid != screenshot_pinfo.pi.dwProcessId)
return TRUE;
if(!IsWindowVisible(hwnd))
return TRUE;
prefix = (char*)lparam;
len = SDL_strlen(prefix) + 100;
filename = (char*)SDL_malloc(len * sizeof(char));
if(!filename)
{
SDLTest_LogError("malloc() failed");
return FALSE;
}
/* restore the window and bring it to the top */
ShowWindowAsync(hwnd, SW_RESTORE);
/* restore is not instantaneous */
SDL_Delay(500);
/* take a screenshot of the client area */
if(img_num == 1)
SDL_snprintf(filename, len, "%s.bmp", prefix);
else
SDL_snprintf(filename, len, "%s_%d.bmp", prefix, img_num);
img_num++;
ScreenshotWindow(hwnd, filename, SDL_TRUE);
SDL_free(filename);
return TRUE;
}
/* each window of the process will have a screenshot taken. The file name will be
prefix-i.png for the i'th window. */
int
SDLVisualTest_ScreenshotProcess(SDL_ProcessInfo* pinfo, char* prefix)
{
if(!pinfo)
{
SDLTest_LogError("pinfo argument cannot be NULL");
return 0;
}
if(!prefix)
{
SDLTest_LogError("prefix argument cannot be NULL");
return 0;
}
img_num = 1;
screenshot_pinfo = *pinfo;
if(!EnumWindows(ScreenshotHwnd, (LPARAM)prefix))
{
SDLTest_LogError("EnumWindows() failed");
return 0;
}
return 1;
}
#endif