diff options
Diffstat (limited to 'libraries/ecore/src/lib/ecore/ecore_exe_win32.c')
-rw-r--r-- | libraries/ecore/src/lib/ecore/ecore_exe_win32.c | 1055 |
1 files changed, 1055 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore/ecore_exe_win32.c b/libraries/ecore/src/lib/ecore/ecore_exe_win32.c new file mode 100644 index 0000000..1f5cb4e --- /dev/null +++ b/libraries/ecore/src/lib/ecore/ecore_exe_win32.c | |||
@@ -0,0 +1,1055 @@ | |||
1 | /* | ||
2 | * TODO: | ||
3 | * - manage I/O pipes (several ones, and stdin) | ||
4 | * - manage SetConsoleCtrlHandler ? | ||
5 | * - the child process seems to still run after the DEL event | ||
6 | * - add log messages | ||
7 | */ | ||
8 | |||
9 | #ifdef HAVE_CONFIG_H | ||
10 | # include <config.h> | ||
11 | #endif | ||
12 | |||
13 | #ifdef HAVE_EVIL | ||
14 | # include <Evil.h> | ||
15 | #endif | ||
16 | |||
17 | #include "Ecore.h" | ||
18 | #include "ecore_private.h" | ||
19 | |||
20 | #define WIN32_LEAN_AND_MEAN | ||
21 | #include <windows.h> | ||
22 | #undef WIN32_LEAN_AND_MEAN | ||
23 | #include <process.h> | ||
24 | |||
25 | #define ECORE_EXE_WIN32_TIMEOUT 3000 | ||
26 | |||
27 | typedef enum | ||
28 | { | ||
29 | ECORE_EXE_WIN32_SIGINT, | ||
30 | ECORE_EXE_WIN32_SIGQUIT, | ||
31 | ECORE_EXE_WIN32_SIGTERM, | ||
32 | ECORE_EXE_WIN32_SIGKILL | ||
33 | } Ecore_Exe_Win32_Signal; | ||
34 | |||
35 | struct _Ecore_Exe | ||
36 | { | ||
37 | EINA_INLIST; | ||
38 | ECORE_MAGIC; | ||
39 | |||
40 | HANDLE process2; | ||
41 | HANDLE process; /* CloseHandle */ | ||
42 | HANDLE process_thread; | ||
43 | DWORD process_id; | ||
44 | DWORD thread_id; | ||
45 | void *data; | ||
46 | char *tag; | ||
47 | char *cmd; | ||
48 | Ecore_Exe_Flags flags; | ||
49 | Ecore_Exe_Win32_Signal sig; | ||
50 | Ecore_Win32_Handler *h_close; | ||
51 | struct | ||
52 | { | ||
53 | HANDLE child_pipe; | ||
54 | HANDLE child_pipe_x; | ||
55 | Ecore_Pipe *p; | ||
56 | HANDLE thread; | ||
57 | void *data_buf; | ||
58 | int data_size; | ||
59 | } pipe_read; | ||
60 | struct | ||
61 | { | ||
62 | HANDLE child_pipe; | ||
63 | HANDLE child_pipe_x; | ||
64 | HANDLE thread; | ||
65 | Ecore_Win32_Handler *h; | ||
66 | void *data_buf; | ||
67 | int data_size; | ||
68 | } pipe_write; | ||
69 | struct | ||
70 | { | ||
71 | HANDLE child_pipe; | ||
72 | HANDLE child_pipe_x; | ||
73 | Ecore_Pipe *p; | ||
74 | HANDLE thread; | ||
75 | void *data_buf; | ||
76 | int data_size; | ||
77 | } pipe_error; | ||
78 | Eina_Bool close_stdin : 1; | ||
79 | Eina_Bool is_suspended : 1; | ||
80 | |||
81 | Ecore_Exe_Cb pre_free_cb; | ||
82 | }; | ||
83 | |||
84 | static Ecore_Exe *exes = NULL; | ||
85 | |||
86 | static int _ecore_exe_win32_pipes_set(Ecore_Exe *exe); | ||
87 | static void _ecore_exe_win32_pipes_close(Ecore_Exe *exe); | ||
88 | |||
89 | static BOOL CALLBACK _ecore_exe_enum_windows_procedure(HWND window, | ||
90 | LPARAM data); | ||
91 | static void _ecore_exe_event_add_free(void *data, | ||
92 | void *ev); | ||
93 | static void _ecore_exe_event_del_free(void *data, | ||
94 | void *ev); | ||
95 | static void _ecore_exe_event_exe_data_free(void *data, | ||
96 | void *ev); | ||
97 | static int _ecore_exe_win32_pipe_thread_generic_cb(void *data, | ||
98 | Ecore_Exe_Flags flags); | ||
99 | static DWORD WINAPI _ecore_exe_win32_pipe_thread_read_cb(void *data); | ||
100 | static DWORD WINAPI _ecore_exe_win32_pipe_thread_error_cb(void *data); | ||
101 | static Eina_Bool _ecore_exe_close_cb(void *data, | ||
102 | Ecore_Win32_Handler *wh); | ||
103 | static void _ecore_exe_pipe_read_cb(void *data, | ||
104 | void *buf, | ||
105 | unsigned int size); | ||
106 | static int _ecore_exe_pipe_write_cb(void *data, | ||
107 | Ecore_Win32_Handler *wh); | ||
108 | static void _ecore_exe_pipe_error_cb(void *data, | ||
109 | void *buf, | ||
110 | unsigned int size); | ||
111 | |||
112 | EAPI int ECORE_EXE_EVENT_ADD = 0; | ||
113 | EAPI int ECORE_EXE_EVENT_DEL = 0; | ||
114 | EAPI int ECORE_EXE_EVENT_DATA = 0; | ||
115 | EAPI int ECORE_EXE_EVENT_ERROR = 0; | ||
116 | |||
117 | void | ||
118 | _ecore_exe_init(void) | ||
119 | { | ||
120 | ECORE_EXE_EVENT_ADD = ecore_event_type_new(); | ||
121 | ECORE_EXE_EVENT_DEL = ecore_event_type_new(); | ||
122 | ECORE_EXE_EVENT_DATA = ecore_event_type_new(); | ||
123 | ECORE_EXE_EVENT_ERROR = ecore_event_type_new(); | ||
124 | } | ||
125 | |||
126 | void | ||
127 | _ecore_exe_shutdown(void) | ||
128 | { | ||
129 | while (exes) | ||
130 | ecore_exe_free(exes); | ||
131 | } | ||
132 | |||
133 | static int run_pri = NORMAL_PRIORITY_CLASS; | ||
134 | |||
135 | EAPI void | ||
136 | ecore_exe_run_priority_set(int pri) | ||
137 | { | ||
138 | switch (pri) | ||
139 | { | ||
140 | case ECORE_EXE_WIN32_PRIORITY_IDLE: | ||
141 | run_pri = IDLE_PRIORITY_CLASS; | ||
142 | break; | ||
143 | |||
144 | case ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL: | ||
145 | run_pri = BELOW_NORMAL_PRIORITY_CLASS; | ||
146 | break; | ||
147 | |||
148 | case ECORE_EXE_WIN32_PRIORITY_NORMAL: | ||
149 | run_pri = NORMAL_PRIORITY_CLASS; | ||
150 | break; | ||
151 | |||
152 | case ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL: | ||
153 | run_pri = ABOVE_NORMAL_PRIORITY_CLASS; | ||
154 | break; | ||
155 | |||
156 | case ECORE_EXE_WIN32_PRIORITY_HIGH: | ||
157 | run_pri = HIGH_PRIORITY_CLASS; | ||
158 | break; | ||
159 | |||
160 | case ECORE_EXE_WIN32_PRIORITY_REALTIME: | ||
161 | run_pri = REALTIME_PRIORITY_CLASS; | ||
162 | break; | ||
163 | |||
164 | default: | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | EAPI int | ||
170 | ecore_exe_run_priority_get(void) | ||
171 | { | ||
172 | switch (run_pri) | ||
173 | { | ||
174 | case IDLE_PRIORITY_CLASS: | ||
175 | return ECORE_EXE_WIN32_PRIORITY_IDLE; | ||
176 | |||
177 | case BELOW_NORMAL_PRIORITY_CLASS: | ||
178 | return ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL; | ||
179 | |||
180 | case NORMAL_PRIORITY_CLASS: | ||
181 | return ECORE_EXE_WIN32_PRIORITY_NORMAL; | ||
182 | |||
183 | case ABOVE_NORMAL_PRIORITY_CLASS: | ||
184 | return ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL; | ||
185 | |||
186 | case HIGH_PRIORITY_CLASS: | ||
187 | return ECORE_EXE_WIN32_PRIORITY_HIGH; | ||
188 | |||
189 | case REALTIME_PRIORITY_CLASS: | ||
190 | return ECORE_EXE_WIN32_PRIORITY_REALTIME; | ||
191 | |||
192 | /* default should not be reached */ | ||
193 | default: | ||
194 | return ECORE_EXE_WIN32_PRIORITY_NORMAL; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | EAPI Ecore_Exe * | ||
199 | ecore_exe_run(const char *exe_cmd, | ||
200 | const void *data) | ||
201 | { | ||
202 | return ecore_exe_pipe_run(exe_cmd, 0, data); | ||
203 | } | ||
204 | |||
205 | EAPI Ecore_Exe * | ||
206 | ecore_exe_pipe_run(const char *exe_cmd, | ||
207 | Ecore_Exe_Flags flags, | ||
208 | const void *data) | ||
209 | { | ||
210 | STARTUPINFO si; | ||
211 | PROCESS_INFORMATION pi; | ||
212 | Ecore_Exe_Event_Add *e; | ||
213 | Ecore_Exe *exe; | ||
214 | char *ret = NULL; | ||
215 | |||
216 | exe = calloc(1, sizeof(Ecore_Exe)); | ||
217 | if (!exe) | ||
218 | return NULL; | ||
219 | |||
220 | if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR)) | ||
221 | && (!(flags & ECORE_EXE_PIPE_READ))) | ||
222 | /* We need something to auto pipe. */ | ||
223 | flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR; | ||
224 | |||
225 | exe->flags = flags; | ||
226 | if (exe->flags & ECORE_EXE_PIPE_READ) | ||
227 | if (!_ecore_exe_win32_pipes_set(exe)) | ||
228 | goto free_exe; | ||
229 | |||
230 | if (exe->flags & ECORE_EXE_PIPE_WRITE) | ||
231 | if (!_ecore_exe_win32_pipes_set(exe)) | ||
232 | goto close_pipes; | ||
233 | |||
234 | if (exe->flags & ECORE_EXE_PIPE_ERROR) | ||
235 | if (!_ecore_exe_win32_pipes_set(exe)) | ||
236 | goto close_pipes; | ||
237 | |||
238 | if ((exe->flags & ECORE_EXE_USE_SH) || | ||
239 | ((ret = strrstr(exe_cmd, ".bat")) && (ret[4] == '\0'))) | ||
240 | { | ||
241 | char buf[PATH_MAX]; | ||
242 | snprintf(buf, PATH_MAX, "cmd.exe /c %s", exe_cmd); | ||
243 | exe->cmd = strdup(buf); | ||
244 | } | ||
245 | else | ||
246 | exe->cmd = strdup(exe_cmd); | ||
247 | |||
248 | if (!exe->cmd) | ||
249 | goto close_pipes; | ||
250 | |||
251 | ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); | ||
252 | |||
253 | ZeroMemory(&si, sizeof(STARTUPINFO)); | ||
254 | si.cb = sizeof(STARTUPINFO); | ||
255 | si.hStdOutput = exe->pipe_read.child_pipe_x; | ||
256 | si.hStdInput = exe->pipe_write.child_pipe; | ||
257 | si.hStdError = exe->pipe_error.child_pipe_x; | ||
258 | si.dwFlags |= STARTF_USESTDHANDLES; | ||
259 | |||
260 | /* FIXME: gerer la priorite */ | ||
261 | |||
262 | if (!CreateProcess(NULL, exe->cmd, NULL, NULL, EINA_TRUE, | ||
263 | run_pri | CREATE_SUSPENDED, NULL, NULL, &si, &pi)) | ||
264 | goto free_exe_cmd; | ||
265 | |||
266 | /* be sure that the child process is running */ | ||
267 | /* FIXME: This does not work if the child is an EFL-based app */ | ||
268 | /* if (WaitForInputIdle(pi.hProcess, INFINITE) == WAIT_FAILED) */ | ||
269 | /* goto free_exe_cmd; */ | ||
270 | |||
271 | ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); | ||
272 | exe->process = pi.hProcess; | ||
273 | exe->process_thread = pi.hThread; | ||
274 | exe->process_id = pi.dwProcessId; | ||
275 | exe->thread_id = pi.dwThreadId; | ||
276 | exe->data = (void *)data; | ||
277 | |||
278 | if (!(exe->process2 = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME | PROCESS_TERMINATE | SYNCHRONIZE, | ||
279 | EINA_FALSE, pi.dwProcessId))) | ||
280 | goto close_thread; | ||
281 | |||
282 | exe->h_close = ecore_main_win32_handler_add(exe->process2, _ecore_exe_close_cb, exe); | ||
283 | if (!exe->h_close) goto close_process2; | ||
284 | |||
285 | if (ResumeThread(exe->process_thread) == ((DWORD)-1)) | ||
286 | goto close_process2; | ||
287 | |||
288 | exes = (Ecore_Exe *)eina_inlist_append(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe)); | ||
289 | |||
290 | e = (Ecore_Exe_Event_Add *)calloc(1, sizeof(Ecore_Exe_Event_Add)); | ||
291 | if (!e) goto delete_h_close; | ||
292 | |||
293 | e->exe = exe; | ||
294 | ecore_event_add(ECORE_EXE_EVENT_ADD, e, | ||
295 | _ecore_exe_event_add_free, NULL); | ||
296 | |||
297 | return exe; | ||
298 | |||
299 | delete_h_close: | ||
300 | ecore_main_win32_handler_del(exe->h_close); | ||
301 | close_process2: | ||
302 | CloseHandle(exe->process2); | ||
303 | close_thread: | ||
304 | CloseHandle(exe->process_thread); | ||
305 | CloseHandle(exe->process); | ||
306 | free_exe_cmd: | ||
307 | free(exe->cmd); | ||
308 | close_pipes: | ||
309 | _ecore_exe_win32_pipes_close(exe); | ||
310 | free_exe: | ||
311 | free(exe); | ||
312 | return NULL; | ||
313 | } | ||
314 | |||
315 | EAPI void | ||
316 | ecore_exe_callback_pre_free_set(Ecore_Exe *exe, | ||
317 | Ecore_Exe_Cb func) | ||
318 | { | ||
319 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
320 | { | ||
321 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, | ||
322 | "ecore_exe_callback_pre_free_set"); | ||
323 | return; | ||
324 | } | ||
325 | exe->pre_free_cb = func; | ||
326 | } | ||
327 | |||
328 | EAPI Eina_Bool | ||
329 | ecore_exe_send(Ecore_Exe *exe, | ||
330 | const void *data, | ||
331 | int size) | ||
332 | { | ||
333 | void *buf; | ||
334 | |||
335 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
336 | { | ||
337 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_send"); | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | if (exe->close_stdin) | ||
342 | { | ||
343 | ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p", | ||
344 | exe, size, data); | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | if (!exe->pipe_write.child_pipe) | ||
349 | { | ||
350 | ERR("Ecore_Exe %p created without ECORE_EXE_PIPE_WRITE! " | ||
351 | "Cannot send %d bytes from %p", exe, size, data); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | buf = realloc(exe->pipe_write.data_buf, exe->pipe_write.data_size + size); | ||
356 | if (!buf) return 0; | ||
357 | |||
358 | exe->pipe_write.data_buf = buf; | ||
359 | memcpy((char *)exe->pipe_write.data_buf + exe->pipe_write.data_size, data, size); | ||
360 | exe->pipe_write.data_size += size; | ||
361 | |||
362 | /* if (exe->pipe_write.) */ | ||
363 | /* ecore_main_fd_handler_active_set(exe->pipe_write.h, ECORE_FD_WRITE); */ | ||
364 | |||
365 | return 1; | ||
366 | } | ||
367 | |||
368 | EAPI void | ||
369 | ecore_exe_close_stdin(Ecore_Exe *exe) | ||
370 | { | ||
371 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
372 | { | ||
373 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_close_stdin"); | ||
374 | return; | ||
375 | } | ||
376 | exe->close_stdin = 1; | ||
377 | } | ||
378 | |||
379 | /* Not used on Windows */ | ||
380 | EAPI void | ||
381 | ecore_exe_auto_limits_set(Ecore_Exe *exe __UNUSED__, | ||
382 | int start_bytes __UNUSED__, | ||
383 | int end_bytes __UNUSED__, | ||
384 | int start_lines __UNUSED__, | ||
385 | int end_lines __UNUSED__) | ||
386 | { | ||
387 | } | ||
388 | |||
389 | EAPI Ecore_Exe_Event_Data * | ||
390 | ecore_exe_event_data_get(Ecore_Exe *exe, | ||
391 | Ecore_Exe_Flags flags) | ||
392 | { | ||
393 | Ecore_Exe_Event_Data *e = NULL; | ||
394 | unsigned char *inbuf; | ||
395 | int inbuf_num; | ||
396 | |||
397 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
398 | { | ||
399 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_event_data_get"); | ||
400 | return NULL; | ||
401 | } | ||
402 | |||
403 | /* Sort out what sort of event we are, */ | ||
404 | /* And get the data. */ | ||
405 | if (flags & ECORE_EXE_PIPE_READ) | ||
406 | { | ||
407 | inbuf = exe->pipe_read.data_buf; | ||
408 | inbuf_num = exe->pipe_read.data_size; | ||
409 | exe->pipe_read.data_buf = NULL; | ||
410 | exe->pipe_read.data_size = 0; | ||
411 | } | ||
412 | else | ||
413 | { | ||
414 | inbuf = exe->pipe_error.data_buf; | ||
415 | inbuf_num = exe->pipe_error.data_size; | ||
416 | exe->pipe_error.data_buf = NULL; | ||
417 | exe->pipe_error.data_size = 0; | ||
418 | } | ||
419 | |||
420 | e = calloc(1, sizeof(Ecore_Exe_Event_Data)); | ||
421 | if (e) | ||
422 | { | ||
423 | e->exe = exe; | ||
424 | e->data = inbuf; | ||
425 | e->size = inbuf_num; | ||
426 | } | ||
427 | |||
428 | return e; | ||
429 | } | ||
430 | |||
431 | EAPI void | ||
432 | ecore_exe_event_data_free(Ecore_Exe_Event_Data *e) | ||
433 | { | ||
434 | if (!e) return; | ||
435 | IF_FREE(e->lines); | ||
436 | IF_FREE(e->data); | ||
437 | free(e); | ||
438 | } | ||
439 | |||
440 | EAPI void * | ||
441 | ecore_exe_free(Ecore_Exe *exe) | ||
442 | { | ||
443 | void *data; | ||
444 | |||
445 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
446 | { | ||
447 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_free"); | ||
448 | return NULL; | ||
449 | } | ||
450 | |||
451 | data = exe->data; | ||
452 | |||
453 | if (exe->pre_free_cb) | ||
454 | exe->pre_free_cb(data, exe); | ||
455 | |||
456 | CloseHandle(exe->process2); | ||
457 | CloseHandle(exe->process_thread); | ||
458 | CloseHandle(exe->process); | ||
459 | free(exe->cmd); | ||
460 | _ecore_exe_win32_pipes_close(exe); | ||
461 | exes = (Ecore_Exe *)eina_inlist_remove(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe)); | ||
462 | ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE); | ||
463 | if (exe->tag) free(exe->tag); | ||
464 | free(exe); | ||
465 | |||
466 | return data; | ||
467 | } | ||
468 | |||
469 | EAPI pid_t | ||
470 | ecore_exe_pid_get(const Ecore_Exe *exe) | ||
471 | { | ||
472 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
473 | { | ||
474 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pid_get"); | ||
475 | return -1; | ||
476 | } | ||
477 | return exe->process_id; | ||
478 | } | ||
479 | |||
480 | EAPI void | ||
481 | ecore_exe_tag_set(Ecore_Exe *exe, | ||
482 | const char *tag) | ||
483 | { | ||
484 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
485 | { | ||
486 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set"); | ||
487 | return; | ||
488 | } | ||
489 | IF_FREE(exe->tag); | ||
490 | if (tag) | ||
491 | exe->tag = strdup(tag); | ||
492 | } | ||
493 | |||
494 | EAPI const char * | ||
495 | ecore_exe_tag_get(const Ecore_Exe *exe) | ||
496 | { | ||
497 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
498 | { | ||
499 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get"); | ||
500 | return NULL; | ||
501 | } | ||
502 | return exe->tag; | ||
503 | } | ||
504 | |||
505 | EAPI const char * | ||
506 | ecore_exe_cmd_get(const Ecore_Exe *exe) | ||
507 | { | ||
508 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
509 | { | ||
510 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_cmd_get"); | ||
511 | return NULL; | ||
512 | } | ||
513 | return exe->cmd; | ||
514 | } | ||
515 | |||
516 | EAPI void * | ||
517 | ecore_exe_data_get(const Ecore_Exe *exe) | ||
518 | { | ||
519 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
520 | { | ||
521 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); | ||
522 | return NULL; | ||
523 | } | ||
524 | return exe->data; | ||
525 | } | ||
526 | |||
527 | EAPI Ecore_Exe_Flags | ||
528 | ecore_exe_flags_get(const Ecore_Exe *exe) | ||
529 | { | ||
530 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
531 | { | ||
532 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); | ||
533 | return 0; | ||
534 | } | ||
535 | return exe->flags; | ||
536 | } | ||
537 | |||
538 | EAPI void | ||
539 | ecore_exe_pause(Ecore_Exe *exe) | ||
540 | { | ||
541 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
542 | { | ||
543 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pause"); | ||
544 | return; | ||
545 | } | ||
546 | |||
547 | if (exe->is_suspended) | ||
548 | return; | ||
549 | |||
550 | if (SuspendThread(exe->process_thread) != (DWORD)-1) | ||
551 | exe->is_suspended = 1; | ||
552 | } | ||
553 | |||
554 | EAPI void | ||
555 | ecore_exe_continue(Ecore_Exe *exe) | ||
556 | { | ||
557 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
558 | { | ||
559 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_continue"); | ||
560 | return; | ||
561 | } | ||
562 | |||
563 | if (!exe->is_suspended) | ||
564 | return; | ||
565 | |||
566 | if (ResumeThread(exe->process_thread) != (DWORD)-1) | ||
567 | exe->is_suspended = 0; | ||
568 | } | ||
569 | |||
570 | EAPI void | ||
571 | ecore_exe_interrupt(Ecore_Exe *exe) | ||
572 | { | ||
573 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
574 | { | ||
575 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt"); | ||
576 | return; | ||
577 | } | ||
578 | |||
579 | CloseHandle(exe->process_thread); | ||
580 | CloseHandle(exe->process); | ||
581 | exe->sig = ECORE_EXE_WIN32_SIGINT; | ||
582 | while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ; | ||
583 | } | ||
584 | |||
585 | EAPI void | ||
586 | ecore_exe_quit(Ecore_Exe *exe) | ||
587 | { | ||
588 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
589 | { | ||
590 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit"); | ||
591 | return; | ||
592 | } | ||
593 | |||
594 | CloseHandle(exe->process_thread); | ||
595 | CloseHandle(exe->process); | ||
596 | exe->sig = ECORE_EXE_WIN32_SIGQUIT; | ||
597 | while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ; | ||
598 | } | ||
599 | |||
600 | EAPI void | ||
601 | ecore_exe_terminate(Ecore_Exe *exe) | ||
602 | { | ||
603 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
604 | { | ||
605 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate"); | ||
606 | return; | ||
607 | } | ||
608 | |||
609 | /* CloseHandle(exe->thread); */ | ||
610 | CloseHandle(exe->process); | ||
611 | exe->sig = ECORE_EXE_WIN32_SIGTERM; | ||
612 | while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ; | ||
613 | } | ||
614 | |||
615 | EAPI void | ||
616 | ecore_exe_kill(Ecore_Exe *exe) | ||
617 | { | ||
618 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
619 | { | ||
620 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_kill"); | ||
621 | return; | ||
622 | } | ||
623 | |||
624 | CloseHandle(exe->process_thread); | ||
625 | CloseHandle(exe->process); | ||
626 | exe->sig = ECORE_EXE_WIN32_SIGKILL; | ||
627 | while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ; | ||
628 | } | ||
629 | |||
630 | EAPI void | ||
631 | ecore_exe_signal(Ecore_Exe *exe, | ||
632 | int num __UNUSED__) | ||
633 | { | ||
634 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
635 | { | ||
636 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal"); | ||
637 | return; | ||
638 | } | ||
639 | |||
640 | /* does nothing */ | ||
641 | } | ||
642 | |||
643 | EAPI void | ||
644 | ecore_exe_hup(Ecore_Exe *exe) | ||
645 | { | ||
646 | if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) | ||
647 | { | ||
648 | ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup"); | ||
649 | return; | ||
650 | } | ||
651 | |||
652 | /* does nothing */ | ||
653 | } | ||
654 | |||
655 | /* FIXME: manage error mode */ | ||
656 | static int | ||
657 | _ecore_exe_win32_pipe_thread_generic_cb(void *data, | ||
658 | Ecore_Exe_Flags flags) | ||
659 | { | ||
660 | #define BUFSIZE 2048 | ||
661 | char buf[BUFSIZE]; | ||
662 | Ecore_Exe *exe; | ||
663 | char *current_buf = NULL; | ||
664 | HANDLE child_pipe; | ||
665 | Ecore_Pipe *ecore_pipe; | ||
666 | Ecore_Exe_Event_Data *event; | ||
667 | DWORD size; | ||
668 | DWORD current_size = 0; | ||
669 | BOOL res; | ||
670 | |||
671 | exe = (Ecore_Exe *)data; | ||
672 | |||
673 | /* Sort out what sort of handler we are. */ | ||
674 | /* And get any left over data from last time. */ | ||
675 | if ((exe->flags & ECORE_EXE_PIPE_READ) && (flags == ECORE_EXE_PIPE_READ)) | ||
676 | { | ||
677 | child_pipe = exe->pipe_read.child_pipe; | ||
678 | ecore_pipe = exe->pipe_read.p; | ||
679 | flags = ECORE_EXE_PIPE_READ; | ||
680 | } | ||
681 | else if ((exe->flags & ECORE_EXE_PIPE_ERROR) && (flags == ECORE_EXE_PIPE_ERROR)) | ||
682 | { | ||
683 | child_pipe = exe->pipe_error.child_pipe; | ||
684 | ecore_pipe = exe->pipe_error.p; | ||
685 | flags = ECORE_EXE_PIPE_ERROR; | ||
686 | } | ||
687 | else | ||
688 | return 0; | ||
689 | |||
690 | while (1) | ||
691 | { | ||
692 | if (!PeekNamedPipe(child_pipe, buf, sizeof(buf), &size, ¤t_size, NULL)) | ||
693 | continue; | ||
694 | if (size == 0) | ||
695 | continue; | ||
696 | current_buf = (char *)malloc(current_size); | ||
697 | if (!current_buf) | ||
698 | continue; | ||
699 | res = ReadFile(child_pipe, current_buf, current_size, &size, NULL); | ||
700 | if (!res || (size == 0)) | ||
701 | { | ||
702 | free(current_buf); | ||
703 | current_buf = NULL; | ||
704 | continue; | ||
705 | } | ||
706 | if (current_size != size) | ||
707 | { | ||
708 | free(current_buf); | ||
709 | current_buf = NULL; | ||
710 | continue; | ||
711 | } | ||
712 | current_size = size; | ||
713 | |||
714 | if (flags == ECORE_EXE_PIPE_READ) | ||
715 | { | ||
716 | exe->pipe_read.data_buf = current_buf; | ||
717 | exe->pipe_read.data_size = current_size; | ||
718 | } | ||
719 | else | ||
720 | { | ||
721 | exe->pipe_error.data_buf = current_buf; | ||
722 | exe->pipe_error.data_size = current_size; | ||
723 | } | ||
724 | |||
725 | event = ecore_exe_event_data_get(exe, flags); | ||
726 | if (event) | ||
727 | ecore_pipe_write(ecore_pipe, &event, sizeof(event)); | ||
728 | |||
729 | current_buf = NULL; | ||
730 | current_size = 0; | ||
731 | } | ||
732 | |||
733 | return 1; | ||
734 | } | ||
735 | |||
736 | static DWORD WINAPI | ||
737 | _ecore_exe_win32_pipe_thread_read_cb(void *data) | ||
738 | { | ||
739 | return _ecore_exe_win32_pipe_thread_generic_cb(data, ECORE_EXE_PIPE_READ); | ||
740 | } | ||
741 | |||
742 | static DWORD WINAPI | ||
743 | _ecore_exe_win32_pipe_thread_error_cb(void *data) | ||
744 | { | ||
745 | return _ecore_exe_win32_pipe_thread_generic_cb(data, ECORE_EXE_PIPE_ERROR); | ||
746 | } | ||
747 | |||
748 | static int | ||
749 | _ecore_exe_win32_pipes_set(Ecore_Exe *exe) | ||
750 | { | ||
751 | SECURITY_ATTRIBUTES sa; | ||
752 | HANDLE child_pipe; | ||
753 | HANDLE child_pipe_x; | ||
754 | |||
755 | sa.nLength = sizeof(SECURITY_ATTRIBUTES); | ||
756 | sa.bInheritHandle = EINA_TRUE; | ||
757 | sa.lpSecurityDescriptor = NULL; | ||
758 | |||
759 | if (!CreatePipe(&child_pipe, &child_pipe_x, &sa, 0)) | ||
760 | return 0; | ||
761 | if (exe->flags & ECORE_EXE_PIPE_WRITE) | ||
762 | { | ||
763 | if (!SetHandleInformation(child_pipe_x, HANDLE_FLAG_INHERIT, 0)) | ||
764 | goto close_pipe; | ||
765 | } | ||
766 | else | ||
767 | { | ||
768 | if (!SetHandleInformation(child_pipe, HANDLE_FLAG_INHERIT, 0)) | ||
769 | goto close_pipe; | ||
770 | } | ||
771 | |||
772 | if (exe->flags & ECORE_EXE_PIPE_READ) | ||
773 | { | ||
774 | exe->pipe_read.child_pipe = child_pipe; | ||
775 | exe->pipe_read.child_pipe_x = child_pipe_x; | ||
776 | exe->pipe_read.p = ecore_pipe_add(_ecore_exe_pipe_read_cb, exe); | ||
777 | exe->pipe_read.thread = CreateThread(NULL, 0, | ||
778 | _ecore_exe_win32_pipe_thread_read_cb, | ||
779 | exe, 0, NULL); | ||
780 | } | ||
781 | else if (exe->flags & ECORE_EXE_PIPE_WRITE) | ||
782 | { | ||
783 | exe->pipe_write.child_pipe = child_pipe; | ||
784 | exe->pipe_write.child_pipe_x = child_pipe_x; | ||
785 | /* exe->pipe_write.thread = CreateThread(NULL, 0, */ | ||
786 | /* _ecore_exe_win32_pipe_thread_cb, */ | ||
787 | /* exe, 0, NULL); */ | ||
788 | } | ||
789 | else | ||
790 | { | ||
791 | exe->pipe_error.child_pipe = child_pipe; | ||
792 | exe->pipe_error.child_pipe_x = child_pipe_x; | ||
793 | exe->pipe_error.p = ecore_pipe_add(_ecore_exe_pipe_error_cb, exe); | ||
794 | exe->pipe_error.thread = CreateThread(NULL, 0, | ||
795 | _ecore_exe_win32_pipe_thread_error_cb, | ||
796 | exe, 0, NULL); | ||
797 | } | ||
798 | |||
799 | return 1; | ||
800 | |||
801 | close_pipe: | ||
802 | CloseHandle(child_pipe); | ||
803 | CloseHandle(child_pipe_x); | ||
804 | |||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | static void | ||
809 | _ecore_exe_win32_pipes_close(Ecore_Exe *exe) | ||
810 | { | ||
811 | if (exe->flags & ECORE_EXE_PIPE_READ) | ||
812 | { | ||
813 | if (exe->pipe_read.child_pipe) | ||
814 | { | ||
815 | CloseHandle(exe->pipe_read.child_pipe); | ||
816 | exe->pipe_read.child_pipe = NULL; | ||
817 | } | ||
818 | if (exe->pipe_read.child_pipe_x) | ||
819 | { | ||
820 | CloseHandle(exe->pipe_read.child_pipe_x); | ||
821 | exe->pipe_read.child_pipe_x = NULL; | ||
822 | } | ||
823 | } | ||
824 | |||
825 | if (exe->flags & ECORE_EXE_PIPE_WRITE) | ||
826 | { | ||
827 | if (exe->pipe_write.child_pipe) | ||
828 | { | ||
829 | CloseHandle(exe->pipe_write.child_pipe); | ||
830 | exe->pipe_write.child_pipe = NULL; | ||
831 | } | ||
832 | if (exe->pipe_write.child_pipe_x) | ||
833 | { | ||
834 | CloseHandle(exe->pipe_write.child_pipe_x); | ||
835 | exe->pipe_write.child_pipe_x = NULL; | ||
836 | } | ||
837 | } | ||
838 | |||
839 | if (exe->flags & ECORE_EXE_PIPE_ERROR) | ||
840 | { | ||
841 | if (exe->pipe_error.child_pipe) | ||
842 | { | ||
843 | CloseHandle(exe->pipe_error.child_pipe); | ||
844 | exe->pipe_error.child_pipe = NULL; | ||
845 | } | ||
846 | if (exe->pipe_error.child_pipe_x) | ||
847 | { | ||
848 | CloseHandle(exe->pipe_error.child_pipe_x); | ||
849 | exe->pipe_error.child_pipe_x = NULL; | ||
850 | } | ||
851 | } | ||
852 | } | ||
853 | |||
854 | static DWORD WINAPI | ||
855 | _ecore_exe_thread_procedure(LPVOID data __UNUSED__) | ||
856 | { | ||
857 | GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); | ||
858 | GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); | ||
859 | return 1; | ||
860 | } | ||
861 | |||
862 | static BOOL CALLBACK | ||
863 | _ecore_exe_enum_windows_procedure(HWND window, | ||
864 | LPARAM data) | ||
865 | { | ||
866 | Ecore_Exe *exe; | ||
867 | DWORD thread_id; | ||
868 | |||
869 | exe = (Ecore_Exe *)data; | ||
870 | thread_id = GetWindowThreadProcessId(window, NULL); | ||
871 | |||
872 | if (thread_id == exe->thread_id) | ||
873 | { | ||
874 | /* Ctrl-C or Ctrl-Break */ | ||
875 | if (CreateRemoteThread(exe->process, NULL, 0, | ||
876 | (LPTHREAD_START_ROUTINE)_ecore_exe_thread_procedure, NULL, | ||
877 | 0, NULL)) | ||
878 | { | ||
879 | printf ("remote thread\n"); | ||
880 | return EINA_FALSE; | ||
881 | } | ||
882 | |||
883 | if ((exe->sig == ECORE_EXE_WIN32_SIGINT) || | ||
884 | (exe->sig == ECORE_EXE_WIN32_SIGQUIT)) | ||
885 | { | ||
886 | printf ("int or quit\n"); | ||
887 | return EINA_FALSE; | ||
888 | } | ||
889 | |||
890 | /* WM_CLOSE message */ | ||
891 | PostMessage(window, WM_CLOSE, 0, 0); | ||
892 | if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0) | ||
893 | { | ||
894 | printf ("CLOSE\n"); | ||
895 | return EINA_FALSE; | ||
896 | } | ||
897 | |||
898 | /* WM_QUIT message */ | ||
899 | PostMessage(window, WM_QUIT, 0, 0); | ||
900 | if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0) | ||
901 | { | ||
902 | printf ("QUIT\n"); | ||
903 | return EINA_FALSE; | ||
904 | } | ||
905 | |||
906 | /* Exit process */ | ||
907 | if (CreateRemoteThread(exe->process, NULL, 0, | ||
908 | (LPTHREAD_START_ROUTINE)ExitProcess, NULL, | ||
909 | 0, NULL)) | ||
910 | { | ||
911 | printf ("remote thread 2\n"); | ||
912 | return EINA_FALSE; | ||
913 | } | ||
914 | |||
915 | if (exe->sig == ECORE_EXE_WIN32_SIGTERM) | ||
916 | { | ||
917 | printf ("term\n"); | ||
918 | return EINA_FALSE; | ||
919 | } | ||
920 | |||
921 | TerminateProcess(exe->process, 0); | ||
922 | |||
923 | return EINA_FALSE; | ||
924 | } | ||
925 | |||
926 | return EINA_TRUE; | ||
927 | } | ||
928 | |||
929 | static void | ||
930 | _ecore_exe_event_add_free(void *data __UNUSED__, | ||
931 | void *ev) | ||
932 | { | ||
933 | Ecore_Exe_Event_Add *e; | ||
934 | |||
935 | e = (Ecore_Exe_Event_Add *)ev; | ||
936 | free(e); | ||
937 | } | ||
938 | |||
939 | static void | ||
940 | _ecore_exe_event_del_free(void *data __UNUSED__, | ||
941 | void *ev) | ||
942 | { | ||
943 | Ecore_Exe_Event_Del *e; | ||
944 | |||
945 | e = (Ecore_Exe_Event_Del *)ev; | ||
946 | if (e->exe) | ||
947 | ecore_exe_free(e->exe); | ||
948 | free(e); | ||
949 | } | ||
950 | |||
951 | static void | ||
952 | _ecore_exe_event_exe_data_free(void *data __UNUSED__, | ||
953 | void *ev) | ||
954 | { | ||
955 | Ecore_Exe_Event_Data *e; | ||
956 | |||
957 | e = (Ecore_Exe_Event_Data *)ev; | ||
958 | ecore_exe_event_data_free(e); | ||
959 | } | ||
960 | |||
961 | static Eina_Bool | ||
962 | _ecore_exe_close_cb(void *data, | ||
963 | Ecore_Win32_Handler *wh __UNUSED__) | ||
964 | { | ||
965 | Ecore_Exe_Event_Del *e; | ||
966 | Ecore_Exe *exe; | ||
967 | DWORD exit_code = 0; | ||
968 | |||
969 | e = calloc(1, sizeof(Ecore_Exe_Event_Del)); | ||
970 | if (!e) return 0; | ||
971 | |||
972 | exe = (Ecore_Exe *)data; | ||
973 | |||
974 | if (GetExitCodeProcess(exe->process2, &exit_code)) | ||
975 | { | ||
976 | e->exit_code = exit_code; | ||
977 | e->exited = 1; | ||
978 | } | ||
979 | else | ||
980 | { | ||
981 | char *msg; | ||
982 | |||
983 | msg = evil_last_error_get(); | ||
984 | printf("%s\n", msg); | ||
985 | free(msg); | ||
986 | } | ||
987 | e->pid = exe->process_id; | ||
988 | e->exe = exe; | ||
989 | |||
990 | ecore_event_add(ECORE_EXE_EVENT_DEL, e, | ||
991 | _ecore_exe_event_del_free, NULL); | ||
992 | |||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | static void | ||
997 | _ecore_exe_pipe_read_cb(void *data, | ||
998 | void *buf, | ||
999 | unsigned int size) | ||
1000 | { | ||
1001 | Ecore_Exe_Event_Data *e; | ||
1002 | |||
1003 | e = *((Ecore_Exe_Event_Data **)buf); | ||
1004 | if (e) | ||
1005 | ecore_event_add(ECORE_EXE_EVENT_DATA, e, | ||
1006 | _ecore_exe_event_exe_data_free, | ||
1007 | NULL); | ||
1008 | } | ||
1009 | |||
1010 | static int | ||
1011 | _ecore_exe_pipe_write_cb(void *data, | ||
1012 | Ecore_Win32_Handler *wh __UNUSED__) | ||
1013 | { | ||
1014 | char buf[READBUFSIZ]; | ||
1015 | Ecore_Exe *exe; | ||
1016 | DWORD num_exe; | ||
1017 | BOOL res; | ||
1018 | |||
1019 | exe = (Ecore_Exe *)data; | ||
1020 | |||
1021 | res = WriteFile(exe->pipe_write.child_pipe_x, buf, READBUFSIZ, &num_exe, NULL); | ||
1022 | if (!res || num_exe == 0) | ||
1023 | { | ||
1024 | /* FIXME: what to do here ?? */ | ||
1025 | } | ||
1026 | |||
1027 | if (exe->close_stdin == 1) | ||
1028 | { | ||
1029 | if (exe->pipe_write.h) | ||
1030 | { | ||
1031 | ecore_main_win32_handler_del(exe->pipe_write.h); | ||
1032 | exe->pipe_write.h = NULL; | ||
1033 | } | ||
1034 | exe->pipe_write.h = NULL; | ||
1035 | CloseHandle(exe->pipe_write.child_pipe); | ||
1036 | exe->pipe_write.child_pipe = NULL; | ||
1037 | } | ||
1038 | |||
1039 | return 1; | ||
1040 | } | ||
1041 | |||
1042 | static void | ||
1043 | _ecore_exe_pipe_error_cb(void *data, | ||
1044 | void *buf, | ||
1045 | unsigned int size) | ||
1046 | { | ||
1047 | Ecore_Exe_Event_Data *e; | ||
1048 | |||
1049 | e = *((Ecore_Exe_Event_Data **)buf); | ||
1050 | if (e) | ||
1051 | ecore_event_add(ECORE_EXE_EVENT_ERROR, e, | ||
1052 | _ecore_exe_event_exe_data_free, | ||
1053 | NULL); | ||
1054 | } | ||
1055 | |||