windows_process.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* See LICENSE.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. #include <SDL.h>
  8. #include <SDL_test.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include "SDL_visualtest_process.h"
  12. #if defined(__WIN32__)
  13. void
  14. LogLastError(const char* str)
  15. {
  16. LPVOID buffer;
  17. DWORD dw = GetLastError();
  18. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|
  19. FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw,
  20. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buffer,
  21. 0, NULL);
  22. SDLTest_LogError("%s: %s", str, (char*)buffer);
  23. LocalFree(buffer);
  24. }
  25. int
  26. SDL_LaunchProcess(char* file, char* args, SDL_ProcessInfo* pinfo)
  27. {
  28. BOOL success;
  29. char* working_directory;
  30. char* command_line;
  31. int path_length, args_length;
  32. STARTUPINFO sui = {0};
  33. sui.cb = sizeof(sui);
  34. if(!file)
  35. {
  36. SDLTest_LogError("Path to executable to launched cannot be NULL.");
  37. return 0;
  38. }
  39. if(!pinfo)
  40. {
  41. SDLTest_LogError("pinfo cannot be NULL.");
  42. return 0;
  43. }
  44. /* get the working directory of the process being launched, so that
  45. the process can load any resources it has in it's working directory */
  46. path_length = SDL_strlen(file);
  47. if(path_length == 0)
  48. {
  49. SDLTest_LogError("Length of the file parameter is zero.");
  50. return 0;
  51. }
  52. working_directory = (char*)SDL_malloc(path_length + 1);
  53. if(!working_directory)
  54. {
  55. SDLTest_LogError("Could not allocate working_directory - SDL_malloc() failed.");
  56. return 0;
  57. }
  58. SDL_memcpy(working_directory, file, path_length + 1);
  59. PathRemoveFileSpec(working_directory);
  60. if(SDL_strlen(working_directory) == 0)
  61. {
  62. SDL_free(working_directory);
  63. working_directory = NULL;
  64. }
  65. /* join the file path and the args string together */
  66. if(!args)
  67. args = "";
  68. args_length = SDL_strlen(args);
  69. command_line = (char*)SDL_malloc(path_length + args_length + 2);
  70. if(!command_line)
  71. {
  72. SDLTest_LogError("Could not allocate command_line - SDL_malloc() failed.");
  73. return 0;
  74. }
  75. SDL_memcpy(command_line, file, path_length);
  76. command_line[path_length] = ' ';
  77. SDL_memcpy(command_line + path_length + 1, args, args_length + 1);
  78. /* create the process */
  79. success = CreateProcess(NULL, command_line, NULL, NULL, FALSE,
  80. NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
  81. NULL, working_directory, &sui, &pinfo->pi);
  82. if(working_directory)
  83. {
  84. SDL_free(working_directory);
  85. working_directory = NULL;
  86. }
  87. SDL_free(command_line);
  88. if(!success)
  89. {
  90. LogLastError("CreateProcess() failed");
  91. return 0;
  92. }
  93. return 1;
  94. }
  95. int
  96. SDL_GetProcessExitStatus(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps)
  97. {
  98. DWORD exit_status;
  99. BOOL success;
  100. if(!pinfo)
  101. {
  102. SDLTest_LogError("pinfo cannot be NULL");
  103. return 0;
  104. }
  105. if(!ps)
  106. {
  107. SDLTest_LogError("ps cannot be NULL");
  108. return 0;
  109. }
  110. /* get the exit code */
  111. success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status);
  112. if(!success)
  113. {
  114. LogLastError("GetExitCodeProcess() failed");
  115. return 0;
  116. }
  117. if(exit_status == STILL_ACTIVE)
  118. ps->exit_status = -1;
  119. else
  120. ps->exit_status = exit_status;
  121. ps->exit_success = 1;
  122. return 1;
  123. }
  124. int
  125. SDL_IsProcessRunning(SDL_ProcessInfo* pinfo)
  126. {
  127. DWORD exit_status;
  128. BOOL success;
  129. if(!pinfo)
  130. {
  131. SDLTest_LogError("pinfo cannot be NULL");
  132. return -1;
  133. }
  134. success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status);
  135. if(!success)
  136. {
  137. LogLastError("GetExitCodeProcess() failed");
  138. return -1;
  139. }
  140. if(exit_status == STILL_ACTIVE)
  141. return 1;
  142. return 0;
  143. }
  144. static BOOL CALLBACK
  145. CloseWindowCallback(HWND hwnd, LPARAM lparam)
  146. {
  147. DWORD pid;
  148. SDL_ProcessInfo* pinfo;
  149. pinfo = (SDL_ProcessInfo*)lparam;
  150. GetWindowThreadProcessId(hwnd, &pid);
  151. if(pid == pinfo->pi.dwProcessId)
  152. {
  153. DWORD_PTR result;
  154. if(!SendMessageTimeout(hwnd, WM_CLOSE, 0, 0, SMTO_BLOCK,
  155. 1000, &result))
  156. {
  157. if(GetLastError() != ERROR_TIMEOUT)
  158. {
  159. LogLastError("SendMessageTimeout() failed");
  160. return FALSE;
  161. }
  162. }
  163. }
  164. return TRUE;
  165. }
  166. int
  167. SDL_QuitProcess(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps)
  168. {
  169. DWORD wait_result;
  170. if(!pinfo)
  171. {
  172. SDLTest_LogError("pinfo argument cannot be NULL");
  173. return 0;
  174. }
  175. if(!ps)
  176. {
  177. SDLTest_LogError("ps argument cannot be NULL");
  178. return 0;
  179. }
  180. /* enumerate through all the windows, trying to close each one */
  181. if(!EnumWindows(CloseWindowCallback, (LPARAM)pinfo))
  182. {
  183. SDLTest_LogError("EnumWindows() failed");
  184. return 0;
  185. }
  186. /* wait until the process terminates */
  187. wait_result = WaitForSingleObject(pinfo->pi.hProcess, 1000);
  188. if(wait_result == WAIT_FAILED)
  189. {
  190. LogLastError("WaitForSingleObject() failed");
  191. return 0;
  192. }
  193. if(wait_result != WAIT_OBJECT_0)
  194. {
  195. SDLTest_LogError("Process did not quit.");
  196. return 0;
  197. }
  198. /* get the exit code */
  199. if(!SDL_GetProcessExitStatus(pinfo, ps))
  200. {
  201. SDLTest_LogError("SDL_GetProcessExitStatus() failed");
  202. return 0;
  203. }
  204. return 1;
  205. }
  206. int
  207. SDL_KillProcess(SDL_ProcessInfo* pinfo, SDL_ProcessExitStatus* ps)
  208. {
  209. BOOL success;
  210. DWORD exit_status, wait_result;
  211. if(!pinfo)
  212. {
  213. SDLTest_LogError("pinfo argument cannot be NULL");
  214. return 0;
  215. }
  216. if(!ps)
  217. {
  218. SDLTest_LogError("ps argument cannot be NULL");
  219. return 0;
  220. }
  221. /* initiate termination of the process */
  222. success = TerminateProcess(pinfo->pi.hProcess, 0);
  223. if(!success)
  224. {
  225. LogLastError("TerminateProcess() failed");
  226. return 0;
  227. }
  228. /* wait until the process terminates */
  229. wait_result = WaitForSingleObject(pinfo->pi.hProcess, INFINITE);
  230. if(wait_result == WAIT_FAILED)
  231. {
  232. LogLastError("WaitForSingleObject() failed");
  233. return 0;
  234. }
  235. /* get the exit code */
  236. success = GetExitCodeProcess(pinfo->pi.hProcess, &exit_status);
  237. if(!success)
  238. {
  239. LogLastError("GetExitCodeProcess() failed");
  240. return 0;
  241. }
  242. ps->exit_status = exit_status;
  243. ps->exit_success = 1;
  244. return 1;
  245. }
  246. #endif