/* * TODO: * - manage I/O pipes (several ones, and stdin) * - manage SetConsoleCtrlHandler ? * - the child process seems to still run after the DEL event * - add log messages */ #ifdef HAVE_CONFIG_H # include #endif #ifdef HAVE_EVIL # include #endif #include "Ecore.h" #include "ecore_private.h" #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #include #define ECORE_EXE_WIN32_TIMEOUT 3000 typedef enum { ECORE_EXE_WIN32_SIGINT, ECORE_EXE_WIN32_SIGQUIT, ECORE_EXE_WIN32_SIGTERM, ECORE_EXE_WIN32_SIGKILL } Ecore_Exe_Win32_Signal; struct _Ecore_Exe { EINA_INLIST; ECORE_MAGIC; HANDLE process2; HANDLE process; /* CloseHandle */ HANDLE process_thread; DWORD process_id; DWORD thread_id; void *data; char *tag; char *cmd; Ecore_Exe_Flags flags; Ecore_Exe_Win32_Signal sig; Ecore_Win32_Handler *h_close; struct { HANDLE child_pipe; HANDLE child_pipe_x; Ecore_Pipe *p; HANDLE thread; void *data_buf; int data_size; } pipe_read; struct { HANDLE child_pipe; HANDLE child_pipe_x; HANDLE thread; Ecore_Win32_Handler *h; void *data_buf; int data_size; } pipe_write; struct { HANDLE child_pipe; HANDLE child_pipe_x; Ecore_Pipe *p; HANDLE thread; void *data_buf; int data_size; } pipe_error; Eina_Bool close_stdin : 1; Eina_Bool is_suspended : 1; Ecore_Exe_Cb pre_free_cb; }; static Ecore_Exe *exes = NULL; static int _ecore_exe_win32_pipes_set(Ecore_Exe *exe); static void _ecore_exe_win32_pipes_close(Ecore_Exe *exe); static BOOL CALLBACK _ecore_exe_enum_windows_procedure(HWND window, LPARAM data); static void _ecore_exe_event_add_free(void *data, void *ev); static void _ecore_exe_event_del_free(void *data, void *ev); static void _ecore_exe_event_exe_data_free(void *data, void *ev); static int _ecore_exe_win32_pipe_thread_generic_cb(void *data, Ecore_Exe_Flags flags); static DWORD WINAPI _ecore_exe_win32_pipe_thread_read_cb(void *data); static DWORD WINAPI _ecore_exe_win32_pipe_thread_error_cb(void *data); static Eina_Bool _ecore_exe_close_cb(void *data, Ecore_Win32_Handler *wh); static void _ecore_exe_pipe_read_cb(void *data, void *buf, unsigned int size); static int _ecore_exe_pipe_write_cb(void *data, Ecore_Win32_Handler *wh); static void _ecore_exe_pipe_error_cb(void *data, void *buf, unsigned int size); EAPI int ECORE_EXE_EVENT_ADD = 0; EAPI int ECORE_EXE_EVENT_DEL = 0; EAPI int ECORE_EXE_EVENT_DATA = 0; EAPI int ECORE_EXE_EVENT_ERROR = 0; void _ecore_exe_init(void) { ECORE_EXE_EVENT_ADD = ecore_event_type_new(); ECORE_EXE_EVENT_DEL = ecore_event_type_new(); ECORE_EXE_EVENT_DATA = ecore_event_type_new(); ECORE_EXE_EVENT_ERROR = ecore_event_type_new(); } void _ecore_exe_shutdown(void) { while (exes) ecore_exe_free(exes); } static int run_pri = NORMAL_PRIORITY_CLASS; EAPI void ecore_exe_run_priority_set(int pri) { switch (pri) { case ECORE_EXE_WIN32_PRIORITY_IDLE: run_pri = IDLE_PRIORITY_CLASS; break; case ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL: run_pri = BELOW_NORMAL_PRIORITY_CLASS; break; case ECORE_EXE_WIN32_PRIORITY_NORMAL: run_pri = NORMAL_PRIORITY_CLASS; break; case ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL: run_pri = ABOVE_NORMAL_PRIORITY_CLASS; break; case ECORE_EXE_WIN32_PRIORITY_HIGH: run_pri = HIGH_PRIORITY_CLASS; break; case ECORE_EXE_WIN32_PRIORITY_REALTIME: run_pri = REALTIME_PRIORITY_CLASS; break; default: break; } } EAPI int ecore_exe_run_priority_get(void) { switch (run_pri) { case IDLE_PRIORITY_CLASS: return ECORE_EXE_WIN32_PRIORITY_IDLE; case BELOW_NORMAL_PRIORITY_CLASS: return ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL; case NORMAL_PRIORITY_CLASS: return ECORE_EXE_WIN32_PRIORITY_NORMAL; case ABOVE_NORMAL_PRIORITY_CLASS: return ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL; case HIGH_PRIORITY_CLASS: return ECORE_EXE_WIN32_PRIORITY_HIGH; case REALTIME_PRIORITY_CLASS: return ECORE_EXE_WIN32_PRIORITY_REALTIME; /* default should not be reached */ default: return ECORE_EXE_WIN32_PRIORITY_NORMAL; } } EAPI Ecore_Exe * ecore_exe_run(const char *exe_cmd, const void *data) { return ecore_exe_pipe_run(exe_cmd, 0, data); } EAPI Ecore_Exe * ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) { STARTUPINFO si; PROCESS_INFORMATION pi; Ecore_Exe_Event_Add *e; Ecore_Exe *exe; char *ret = NULL; exe = calloc(1, sizeof(Ecore_Exe)); if (!exe) return NULL; if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR)) && (!(flags & ECORE_EXE_PIPE_READ))) /* We need something to auto pipe. */ flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR; exe->flags = flags; if (exe->flags & ECORE_EXE_PIPE_READ) if (!_ecore_exe_win32_pipes_set(exe)) goto free_exe; if (exe->flags & ECORE_EXE_PIPE_WRITE) if (!_ecore_exe_win32_pipes_set(exe)) goto close_pipes; if (exe->flags & ECORE_EXE_PIPE_ERROR) if (!_ecore_exe_win32_pipes_set(exe)) goto close_pipes; if ((exe->flags & ECORE_EXE_USE_SH) || ((ret = strrstr(exe_cmd, ".bat")) && (ret[4] == '\0'))) { char buf[PATH_MAX]; snprintf(buf, PATH_MAX, "cmd.exe /c %s", exe_cmd); exe->cmd = strdup(buf); } else exe->cmd = strdup(exe_cmd); if (!exe->cmd) goto close_pipes; ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.hStdOutput = exe->pipe_read.child_pipe_x; si.hStdInput = exe->pipe_write.child_pipe; si.hStdError = exe->pipe_error.child_pipe_x; si.dwFlags |= STARTF_USESTDHANDLES; /* FIXME: gerer la priorite */ if (!CreateProcess(NULL, exe->cmd, NULL, NULL, EINA_TRUE, run_pri | CREATE_SUSPENDED, NULL, NULL, &si, &pi)) goto free_exe_cmd; /* be sure that the child process is running */ /* FIXME: This does not work if the child is an EFL-based app */ /* if (WaitForInputIdle(pi.hProcess, INFINITE) == WAIT_FAILED) */ /* goto free_exe_cmd; */ ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); exe->process = pi.hProcess; exe->process_thread = pi.hThread; exe->process_id = pi.dwProcessId; exe->thread_id = pi.dwThreadId; exe->data = (void *)data; if (!(exe->process2 = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME | PROCESS_TERMINATE | SYNCHRONIZE, EINA_FALSE, pi.dwProcessId))) goto close_thread; exe->h_close = ecore_main_win32_handler_add(exe->process2, _ecore_exe_close_cb, exe); if (!exe->h_close) goto close_process2; if (ResumeThread(exe->process_thread) == ((DWORD)-1)) goto close_process2; exes = (Ecore_Exe *)eina_inlist_append(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe)); e = (Ecore_Exe_Event_Add *)calloc(1, sizeof(Ecore_Exe_Event_Add)); if (!e) goto delete_h_close; e->exe = exe; ecore_event_add(ECORE_EXE_EVENT_ADD, e, _ecore_exe_event_add_free, NULL); return exe; delete_h_close: ecore_main_win32_handler_del(exe->h_close); close_process2: CloseHandle(exe->process2); close_thread: CloseHandle(exe->process_thread); CloseHandle(exe->process); free_exe_cmd: free(exe->cmd); close_pipes: _ecore_exe_win32_pipes_close(exe); free_exe: free(exe); return NULL; } EAPI void ecore_exe_callback_pre_free_set(Ecore_Exe *exe, Ecore_Exe_Cb func) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_callback_pre_free_set"); return; } exe->pre_free_cb = func; } EAPI Eina_Bool ecore_exe_send(Ecore_Exe *exe, const void *data, int size) { void *buf; if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_send"); return 0; } if (exe->close_stdin) { ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p", exe, size, data); return 0; } if (!exe->pipe_write.child_pipe) { ERR("Ecore_Exe %p created without ECORE_EXE_PIPE_WRITE! " "Cannot send %d bytes from %p", exe, size, data); return 0; } buf = realloc(exe->pipe_write.data_buf, exe->pipe_write.data_size + size); if (buf == NULL) return 0; exe->pipe_write.data_buf = buf; memcpy((char *)exe->pipe_write.data_buf + exe->pipe_write.data_size, data, size); exe->pipe_write.data_size += size; /* if (exe->pipe_write.) */ /* ecore_main_fd_handler_active_set(exe->pipe_write.h, ECORE_FD_WRITE); */ return 1; } EAPI void ecore_exe_close_stdin(Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_close_stdin"); return; } exe->close_stdin = 1; } /* Not used on Windows */ EAPI void ecore_exe_auto_limits_set(Ecore_Exe *exe __UNUSED__, int start_bytes __UNUSED__, int end_bytes __UNUSED__, int start_lines __UNUSED__, int end_lines __UNUSED__) { } EAPI Ecore_Exe_Event_Data * ecore_exe_event_data_get(Ecore_Exe *exe, Ecore_Exe_Flags flags) { Ecore_Exe_Event_Data *e = NULL; unsigned char *inbuf; int inbuf_num; if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_event_data_get"); return NULL; } /* Sort out what sort of event we are, */ /* And get the data. */ if (flags & ECORE_EXE_PIPE_READ) { inbuf = exe->pipe_read.data_buf; inbuf_num = exe->pipe_read.data_size; exe->pipe_read.data_buf = NULL; exe->pipe_read.data_size = 0; } else { inbuf = exe->pipe_error.data_buf; inbuf_num = exe->pipe_error.data_size; exe->pipe_error.data_buf = NULL; exe->pipe_error.data_size = 0; } e = calloc(1, sizeof(Ecore_Exe_Event_Data)); if (e) { e->exe = exe; e->data = inbuf; e->size = inbuf_num; } return e; } EAPI void ecore_exe_event_data_free(Ecore_Exe_Event_Data *e) { if (!e) return; IF_FREE(e->lines); IF_FREE(e->data); free(e); } EAPI void * ecore_exe_free(Ecore_Exe *exe) { void *data; if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_free"); return NULL; } data = exe->data; if (exe->pre_free_cb) exe->pre_free_cb(data, exe); CloseHandle(exe->process2); CloseHandle(exe->process_thread); CloseHandle(exe->process); free(exe->cmd); _ecore_exe_win32_pipes_close(exe); exes = (Ecore_Exe *)eina_inlist_remove(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe)); ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE); if (exe->tag) free(exe->tag); free(exe); return data; } EAPI pid_t ecore_exe_pid_get(const Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pid_get"); return -1; } return exe->process_id; } EAPI void ecore_exe_tag_set(Ecore_Exe *exe, const char *tag) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set"); return; } IF_FREE(exe->tag); if (tag) exe->tag = strdup(tag); } EAPI const char * ecore_exe_tag_get(const Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get"); return NULL; } return exe->tag; } EAPI const char * ecore_exe_cmd_get(const Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_cmd_get"); return NULL; } return exe->cmd; } EAPI void * ecore_exe_data_get(const Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); return NULL; } return exe->data; } EAPI Ecore_Exe_Flags ecore_exe_flags_get(const Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); return 0; } return exe->flags; } EAPI void ecore_exe_pause(Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pause"); return; } if (exe->is_suspended) return; if (SuspendThread(exe->process_thread) != (DWORD)-1) exe->is_suspended = 1; } EAPI void ecore_exe_continue(Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_continue"); return; } if (!exe->is_suspended) return; if (ResumeThread(exe->process_thread) != (DWORD)-1) exe->is_suspended = 0; } EAPI void ecore_exe_interrupt(Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt"); return; } CloseHandle(exe->process_thread); CloseHandle(exe->process); exe->sig = ECORE_EXE_WIN32_SIGINT; while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)); } EAPI void ecore_exe_quit(Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit"); return; } CloseHandle(exe->process_thread); CloseHandle(exe->process); exe->sig = ECORE_EXE_WIN32_SIGQUIT; while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)); } EAPI void ecore_exe_terminate(Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate"); return; } /* CloseHandle(exe->thread); */ CloseHandle(exe->process); exe->sig = ECORE_EXE_WIN32_SIGTERM; while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)); } EAPI void ecore_exe_kill(Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_kill"); return; } CloseHandle(exe->process_thread); CloseHandle(exe->process); exe->sig = ECORE_EXE_WIN32_SIGKILL; while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)); } EAPI void ecore_exe_signal(Ecore_Exe *exe, int num __UNUSED__) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal"); return; } /* does nothing */ } EAPI void ecore_exe_hup(Ecore_Exe *exe) { if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) { ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup"); return; } /* does nothing */ } /* FIXME: manage error mode */ static int _ecore_exe_win32_pipe_thread_generic_cb(void *data, Ecore_Exe_Flags flags) { #define BUFSIZE 2 char buf[BUFSIZE]; Ecore_Exe *exe; char *current_buf = NULL; HANDLE child_pipe; Ecore_Pipe *ecore_pipe; Ecore_Exe_Event_Data *event; DWORD size; DWORD current_size = 0; BOOL res; exe = (Ecore_Exe *)data; /* Sort out what sort of handler we are. */ /* And get any left over data from last time. */ if ((exe->flags & ECORE_EXE_PIPE_READ) && (flags == ECORE_EXE_PIPE_READ)) { child_pipe = exe->pipe_read.child_pipe; ecore_pipe = exe->pipe_read.p; flags = ECORE_EXE_PIPE_READ; } else if ((exe->flags & ECORE_EXE_PIPE_ERROR) && (flags == ECORE_EXE_PIPE_ERROR)) { child_pipe = exe->pipe_error.child_pipe; ecore_pipe = exe->pipe_error.p; flags = ECORE_EXE_PIPE_ERROR; } else return 0; while (1) { if (!PeekNamedPipe(child_pipe, buf, 1, &size, ¤t_size, NULL)) continue; if (size == 0) continue; current_buf = (char *)malloc(current_size); if (!current_buf) continue; res = ReadFile(child_pipe, current_buf, current_size, &size, NULL); if (!res || (size == 0)) { free(current_buf); current_buf = NULL; continue; } if (current_size != size) { free(current_buf); current_buf = NULL; continue; } current_size = size; if (flags == ECORE_EXE_PIPE_READ) { exe->pipe_read.data_buf = current_buf; exe->pipe_read.data_size = current_size; } else { exe->pipe_error.data_buf = current_buf; exe->pipe_error.data_size = current_size; } event = ecore_exe_event_data_get(exe, flags); if (event) ecore_pipe_write(ecore_pipe, &event, sizeof(event)); current_buf = NULL; current_size = 0; } return 1; } static DWORD WINAPI _ecore_exe_win32_pipe_thread_read_cb(void *data) { return _ecore_exe_win32_pipe_thread_generic_cb(data, ECORE_EXE_PIPE_READ); } static DWORD WINAPI _ecore_exe_win32_pipe_thread_error_cb(void *data) { return _ecore_exe_win32_pipe_thread_generic_cb(data, ECORE_EXE_PIPE_ERROR); } static int _ecore_exe_win32_pipes_set(Ecore_Exe *exe) { SECURITY_ATTRIBUTES sa; HANDLE child_pipe; HANDLE child_pipe_x; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = EINA_TRUE; sa.lpSecurityDescriptor = NULL; if (!CreatePipe(&child_pipe, &child_pipe_x, &sa, 0)) return 0; if (exe->flags & ECORE_EXE_PIPE_WRITE) { if (!SetHandleInformation(child_pipe_x, HANDLE_FLAG_INHERIT, 0)) goto close_pipe; } else { if (!SetHandleInformation(child_pipe, HANDLE_FLAG_INHERIT, 0)) goto close_pipe; } if (exe->flags & ECORE_EXE_PIPE_READ) { exe->pipe_read.child_pipe = child_pipe; exe->pipe_read.child_pipe_x = child_pipe_x; exe->pipe_read.p = ecore_pipe_add(_ecore_exe_pipe_read_cb, exe); exe->pipe_read.thread = CreateThread(NULL, 0, _ecore_exe_win32_pipe_thread_read_cb, exe, 0, NULL); } else if (exe->flags & ECORE_EXE_PIPE_WRITE) { exe->pipe_write.child_pipe = child_pipe; exe->pipe_write.child_pipe_x = child_pipe_x; /* exe->pipe_write.thread = CreateThread(NULL, 0, */ /* _ecore_exe_win32_pipe_thread_cb, */ /* exe, 0, NULL); */ } else { exe->pipe_error.child_pipe = child_pipe; exe->pipe_error.child_pipe_x = child_pipe_x; exe->pipe_error.p = ecore_pipe_add(_ecore_exe_pipe_error_cb, exe); exe->pipe_error.thread = CreateThread(NULL, 0, _ecore_exe_win32_pipe_thread_error_cb, exe, 0, NULL); } return 1; close_pipe: CloseHandle(child_pipe); CloseHandle(child_pipe_x); return 0; } static void _ecore_exe_win32_pipes_close(Ecore_Exe *exe) { if (exe->flags & ECORE_EXE_PIPE_READ) { if (exe->pipe_read.child_pipe) { CloseHandle(exe->pipe_read.child_pipe); exe->pipe_read.child_pipe = NULL; } if (exe->pipe_read.child_pipe_x) { CloseHandle(exe->pipe_read.child_pipe_x); exe->pipe_read.child_pipe_x = NULL; } } if (exe->flags & ECORE_EXE_PIPE_WRITE) { if (exe->pipe_write.child_pipe) { CloseHandle(exe->pipe_write.child_pipe); exe->pipe_write.child_pipe = NULL; } if (exe->pipe_write.child_pipe_x) { CloseHandle(exe->pipe_write.child_pipe_x); exe->pipe_write.child_pipe_x = NULL; } } if (exe->flags & ECORE_EXE_PIPE_ERROR) { if (exe->pipe_error.child_pipe) { CloseHandle(exe->pipe_error.child_pipe); exe->pipe_error.child_pipe = NULL; } if (exe->pipe_error.child_pipe_x) { CloseHandle(exe->pipe_error.child_pipe_x); exe->pipe_error.child_pipe_x = NULL; } } } static DWORD WINAPI _ecore_exe_thread_procedure(LPVOID data __UNUSED__) { GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); return 1; } static BOOL CALLBACK _ecore_exe_enum_windows_procedure(HWND window, LPARAM data) { Ecore_Exe *exe; DWORD thread_id; exe = (Ecore_Exe *)data; thread_id = GetWindowThreadProcessId(window, NULL); if (thread_id == exe->thread_id) { /* Ctrl-C or Ctrl-Break */ if (CreateRemoteThread(exe->process, NULL, 0, (LPTHREAD_START_ROUTINE)_ecore_exe_thread_procedure, NULL, 0, NULL)) { printf ("remote thread\n"); return EINA_FALSE; } if ((exe->sig == ECORE_EXE_WIN32_SIGINT) || (exe->sig == ECORE_EXE_WIN32_SIGQUIT)) { printf ("int or quit\n"); return EINA_FALSE; } /* WM_CLOSE message */ PostMessage(window, WM_CLOSE, 0, 0); if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0) { printf ("CLOSE\n"); return EINA_FALSE; } /* WM_QUIT message */ PostMessage(window, WM_QUIT, 0, 0); if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0) { printf ("QUIT\n"); return EINA_FALSE; } /* Exit process */ if (CreateRemoteThread(exe->process, NULL, 0, (LPTHREAD_START_ROUTINE)ExitProcess, NULL, 0, NULL)) { printf ("remote thread 2\n"); return EINA_FALSE; } if (exe->sig == ECORE_EXE_WIN32_SIGTERM) { printf ("term\n"); return EINA_FALSE; } TerminateProcess(exe->process, 0); return EINA_FALSE; } return EINA_TRUE; } static void _ecore_exe_event_add_free(void *data __UNUSED__, void *ev) { Ecore_Exe_Event_Add *e; e = (Ecore_Exe_Event_Add *)ev; free(e); } static void _ecore_exe_event_del_free(void *data __UNUSED__, void *ev) { Ecore_Exe_Event_Del *e; e = (Ecore_Exe_Event_Del *)ev; if (e->exe) ecore_exe_free(e->exe); free(e); } static void _ecore_exe_event_exe_data_free(void *data __UNUSED__, void *ev) { Ecore_Exe_Event_Data *e; e = (Ecore_Exe_Event_Data *)ev; ecore_exe_event_data_free(e); } static Eina_Bool _ecore_exe_close_cb(void *data, Ecore_Win32_Handler *wh __UNUSED__) { Ecore_Exe_Event_Del *e; Ecore_Exe *exe; DWORD exit_code = 0; e = calloc(1, sizeof(Ecore_Exe_Event_Del)); if (!e) return 0; exe = (Ecore_Exe *)data; if (GetExitCodeProcess(exe->process2, &exit_code)) { e->exit_code = exit_code; e->exited = 1; } else { char *msg; msg = evil_last_error_get(); printf("%s\n", msg); free(msg); } e->pid = exe->process_id; e->exe = exe; ecore_event_add(ECORE_EXE_EVENT_DEL, e, _ecore_exe_event_del_free, NULL); return 0; } static void _ecore_exe_pipe_read_cb(void *data, void *buf, unsigned int size) { Ecore_Exe_Event_Data *e; e = *((Ecore_Exe_Event_Data **)buf); if (e) ecore_event_add(ECORE_EXE_EVENT_DATA, e, _ecore_exe_event_exe_data_free, NULL); } static int _ecore_exe_pipe_write_cb(void *data, Ecore_Win32_Handler *wh __UNUSED__) { char buf[READBUFSIZ]; Ecore_Exe *exe; DWORD num_exe; BOOL res; exe = (Ecore_Exe *)data; res = WriteFile(exe->pipe_write.child_pipe_x, buf, READBUFSIZ, &num_exe, NULL); if (!res || num_exe == 0) { /* FIXME: what to do here ?? */ } if (exe->close_stdin == 1) { if (exe->pipe_write.h) { ecore_main_win32_handler_del(exe->pipe_write.h); exe->pipe_write.h = NULL; } exe->pipe_write.h = NULL; CloseHandle(exe->pipe_write.child_pipe); exe->pipe_write.child_pipe = NULL; } return 1; } static void _ecore_exe_pipe_error_cb(void *data, void *buf, unsigned int size) { Ecore_Exe_Event_Data *e; e = *((Ecore_Exe_Event_Data **)buf); if (e) ecore_event_add(ECORE_EXE_EVENT_ERROR, e, _ecore_exe_event_exe_data_free, NULL); }