forked from enlightenment/efl
1056 lines
26 KiB
C
1056 lines
26 KiB
C
/*
|
|
* 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 <config.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_EVIL
|
|
# include <Evil.h>
|
|
#endif
|
|
|
|
#include "Ecore.h"
|
|
#include "ecore_private.h"
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#undef WIN32_LEAN_AND_MEAN
|
|
#include <process.h>
|
|
|
|
#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) 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 EINA_UNUSED,
|
|
int start_bytes EINA_UNUSED,
|
|
int end_bytes EINA_UNUSED,
|
|
int start_lines EINA_UNUSED,
|
|
int end_lines EINA_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 EINA_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 2048
|
|
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, sizeof(buf), &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 EINA_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 EINA_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 EINA_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 EINA_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 EINA_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 EINA_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);
|
|
}
|
|
|