forked from enlightenment/efl
exore_exe: fix from @raster
This commit is contained in:
parent
874071ca42
commit
c505b754ce
|
@ -80,30 +80,27 @@ struct _Ecore_Exe_Data
|
||||||
Ecore_Win32_Handler *h_close;
|
Ecore_Win32_Handler *h_close;
|
||||||
Ecore_Exe_Win32_Signal sig;
|
Ecore_Exe_Win32_Signal sig;
|
||||||
|
|
||||||
struct
|
Ecore_Thread *th;
|
||||||
{
|
|
||||||
|
struct {
|
||||||
HANDLE child_pipe;
|
HANDLE child_pipe;
|
||||||
HANDLE thread;
|
|
||||||
void *data_buf;
|
void *data_buf;
|
||||||
DWORD data_size;
|
int data_size;
|
||||||
} pipe_read;
|
} pipe_read;
|
||||||
|
|
||||||
struct
|
struct {
|
||||||
{
|
HANDLE child_pipe;
|
||||||
|
void *data_buf;
|
||||||
|
int data_size;
|
||||||
|
} pipe_error;
|
||||||
|
|
||||||
|
struct {
|
||||||
HANDLE child_pipe;
|
HANDLE child_pipe;
|
||||||
HANDLE child_pipe_x;
|
HANDLE child_pipe_x;
|
||||||
void *data_buf;
|
void *data_buf;
|
||||||
int data_size;
|
int data_size;
|
||||||
} pipe_write;
|
} pipe_write;
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
HANDLE child_pipe;
|
|
||||||
HANDLE thread;
|
|
||||||
void *data_buf;
|
|
||||||
DWORD data_size;
|
|
||||||
} pipe_error;
|
|
||||||
|
|
||||||
Eina_Bool close_threads : 1;
|
Eina_Bool close_threads : 1;
|
||||||
Eina_Bool is_suspended : 1;
|
Eina_Bool is_suspended : 1;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -40,27 +40,11 @@ static void
|
||||||
_ecore_exe_threads_terminate(Ecore_Exe *obj)
|
_ecore_exe_threads_terminate(Ecore_Exe *obj)
|
||||||
{
|
{
|
||||||
Ecore_Exe_Data *exe = efl_data_scope_get(obj, ECORE_EXE_CLASS);
|
Ecore_Exe_Data *exe = efl_data_scope_get(obj, ECORE_EXE_CLASS);
|
||||||
HANDLE threads[2] = { NULL, NULL };
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (!exe) return;
|
if (!exe) return;
|
||||||
if (exe->pipe_read.thread)
|
if (!exe->th) return;
|
||||||
{
|
ecore_thread_cancel(exe->th);
|
||||||
threads[i] = exe->pipe_read.thread;
|
ecore_thread_wait(exe->th, 0.3);
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (exe->pipe_error.thread)
|
|
||||||
{
|
|
||||||
threads[i] = exe->pipe_error.thread;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
exe->close_threads = 1;
|
|
||||||
WaitForMultipleObjects(i, threads, TRUE, INFINITE);
|
|
||||||
IF_FN_DEL(CloseHandle, exe->pipe_error.thread);
|
|
||||||
IF_FN_DEL(CloseHandle, exe->pipe_read.thread);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Eina_Bool
|
static Eina_Bool
|
||||||
|
@ -81,10 +65,8 @@ _ecore_exe_close_cb(void *data,
|
||||||
/* FIXME : manage the STILL_ACTIVE returned error */
|
/* FIXME : manage the STILL_ACTIVE returned error */
|
||||||
if (!GetExitCodeProcess(exe->process, &exit_code))
|
if (!GetExitCodeProcess(exe->process, &exit_code))
|
||||||
{
|
{
|
||||||
char *msg;
|
char *msg = evil_last_error_get();
|
||||||
|
DBG("%s", msg);
|
||||||
msg = evil_last_error_get();
|
|
||||||
printf("%s\n", msg);
|
|
||||||
free(msg);
|
free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,154 +76,182 @@ _ecore_exe_close_cb(void *data,
|
||||||
e->exe = obj;
|
e->exe = obj;
|
||||||
exe->h_close = NULL; // It's going to get deleted in the next callback.
|
exe->h_close = NULL; // It's going to get deleted in the next callback.
|
||||||
|
|
||||||
ecore_event_add(ECORE_EXE_EVENT_DEL, e,
|
ecore_event_add(ECORE_EXE_EVENT_DEL, e, _ecore_exe_event_del_free, NULL);
|
||||||
_ecore_exe_event_del_free, NULL);
|
|
||||||
|
|
||||||
DBG("Exiting process %s with exit code %d\n", exe->cmd, e->exit_code);
|
DBG("Exiting process %s with exit code %d\n", exe->cmd, e->exit_code);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int __stdcall
|
typedef struct
|
||||||
_ecore_exe_pipe_read_thread_cb(void *data)
|
|
||||||
{
|
{
|
||||||
char buf[64];
|
Ecore_Exe *obj;
|
||||||
Ecore_Exe *obj = data;
|
HANDLE read_pipe;
|
||||||
Ecore_Exe_Data *exe = efl_data_scope_get(obj, ECORE_EXE_CLASS);
|
HANDLE error_pipe;
|
||||||
Ecore_Exe_Event_Data *event_data;
|
Eina_Bool read : 1;
|
||||||
char *current_buf = NULL;
|
Eina_Bool error : 1;
|
||||||
DWORD size;
|
} Threaddata;
|
||||||
DWORD current_size = 0;
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Ecore_Exe *obj;
|
||||||
|
unsigned char *buf;
|
||||||
|
int buf_size;
|
||||||
|
Eina_Bool read : 1;
|
||||||
|
Eina_Bool error : 1;
|
||||||
|
} Threadreply;
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_exe_win32_io_poll_thread(void *data, Ecore_Thread *th)
|
||||||
|
{
|
||||||
|
Threaddata *tdat = data;
|
||||||
|
Threadreply *trep;
|
||||||
|
Eina_Bool data_read, data_write;
|
||||||
|
char buf[4096];
|
||||||
|
DWORD size, current_size;
|
||||||
BOOL res;
|
BOOL res;
|
||||||
|
|
||||||
if (!exe) return 0;
|
while (EINA_TRUE)
|
||||||
while (1)
|
|
||||||
{
|
{
|
||||||
res = PeekNamedPipe(exe->pipe_read.child_pipe,
|
data_read = EINA_FALSE;
|
||||||
buf, sizeof(buf) - 1, &size, ¤t_size, NULL);
|
data_write = EINA_FALSE;
|
||||||
if (!res || (size == 0))
|
|
||||||
|
if (tdat->read)
|
||||||
{
|
{
|
||||||
if (exe->close_threads)
|
res = PeekNamedPipe(tdat->read_pipe, buf, sizeof(buf),
|
||||||
break;
|
&size, ¤t_size, NULL);
|
||||||
|
if (res && (size != 0))
|
||||||
Sleep(100);
|
{
|
||||||
continue;
|
trep = calloc(1, sizeof(Threadreply));
|
||||||
|
if (trep)
|
||||||
|
{
|
||||||
|
trep->obj = tdat->obj;
|
||||||
|
trep->buf = malloc(current_size);
|
||||||
|
if (trep->buf)
|
||||||
|
{
|
||||||
|
res = ReadFile(tdat->read_pipe, trep->buf,
|
||||||
|
current_size, &size, NULL);
|
||||||
|
if (!res || (size == 0))
|
||||||
|
{
|
||||||
|
free(trep->buf);
|
||||||
|
free(trep);
|
||||||
|
}
|
||||||
|
trep->buf_size = size;
|
||||||
|
trep->read = EINA_TRUE;
|
||||||
|
ecore_thread_feedback(th, trep);
|
||||||
|
data_read = EINA_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (tdat->error)
|
||||||
current_buf = (char *)malloc(current_size);
|
|
||||||
if (!current_buf)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
res = ReadFile(exe->pipe_read.child_pipe, current_buf, current_size, &size, NULL);
|
|
||||||
if (!res || (size == 0))
|
|
||||||
{
|
{
|
||||||
free(current_buf);
|
res = PeekNamedPipe(tdat->error_pipe, buf, sizeof(buf),
|
||||||
current_buf = NULL;
|
&size, ¤t_size, NULL);
|
||||||
continue;
|
if (res && (size != 0))
|
||||||
|
{
|
||||||
|
trep = calloc(1, sizeof(Threadreply));
|
||||||
|
if (trep)
|
||||||
|
{
|
||||||
|
trep->obj = tdat->obj;
|
||||||
|
trep->buf = malloc(current_size);
|
||||||
|
if (trep->buf)
|
||||||
|
{
|
||||||
|
res = ReadFile(tdat->error_pipe, trep->buf,
|
||||||
|
current_size, &size, NULL);
|
||||||
|
if (!res || (size == 0))
|
||||||
|
{
|
||||||
|
free(trep->buf);
|
||||||
|
free(trep);
|
||||||
|
}
|
||||||
|
trep->buf_size = size;
|
||||||
|
trep->error = EINA_TRUE;
|
||||||
|
ecore_thread_feedback(th, trep);
|
||||||
|
//data_error = EINA_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (ecore_thread_check(th)) break;
|
||||||
current_size = size;
|
if (!(data_read || data_write)) Sleep(100);
|
||||||
|
else if (ecore_thread_check(th)) break;
|
||||||
if (!exe->pipe_read.data_buf)
|
|
||||||
{
|
|
||||||
exe->pipe_read.data_buf = current_buf;
|
|
||||||
exe->pipe_read.data_size = current_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exe->pipe_read.data_buf = realloc(exe->pipe_read.data_buf, exe->pipe_read.data_size + current_size);
|
|
||||||
memcpy((unsigned char *)exe->pipe_read.data_buf + exe->pipe_read.data_size, current_buf, current_size);
|
|
||||||
exe->pipe_read.data_size += current_size;
|
|
||||||
free(current_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
event_data = ecore_exe_event_data_get(obj, ECORE_EXE_PIPE_READ);
|
|
||||||
if (event_data)
|
|
||||||
{
|
|
||||||
ecore_event_add(ECORE_EXE_EVENT_DATA, event_data,
|
|
||||||
_ecore_exe_event_exe_data_free,
|
|
||||||
NULL);
|
|
||||||
efl_event_callback_call(obj, ECORE_EXE_EVENT_DATA_GET, event_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
current_buf = NULL;
|
|
||||||
current_size = 0;
|
|
||||||
}
|
}
|
||||||
|
free(tdat);
|
||||||
_endthreadex(0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int __stdcall
|
static void
|
||||||
_ecore_exe_pipe_error_thread_cb(void *data)
|
_ecore_exe_win32_io_poll_notify(void *data EINA_UNUSED,
|
||||||
|
Ecore_Thread *th EINA_UNUSED, void *msg)
|
||||||
{
|
{
|
||||||
char buf[64];
|
Threadreply *trep = msg;
|
||||||
Ecore_Exe *obj = data;
|
Ecore_Exe *obj = trep->obj;
|
||||||
Ecore_Exe_Data *exe = efl_data_scope_get(obj, ECORE_EXE_CLASS);
|
Ecore_Exe_Data *exe = efl_data_scope_get(obj, ECORE_EXE_CLASS);
|
||||||
Ecore_Exe_Event_Data *event_data;
|
unsigned char *b;
|
||||||
char *current_buf = NULL;
|
|
||||||
DWORD size;
|
|
||||||
DWORD current_size = 0;
|
|
||||||
BOOL res;
|
|
||||||
|
|
||||||
if (!exe) return 0;
|
if (exe)
|
||||||
while (1)
|
|
||||||
{
|
{
|
||||||
res = PeekNamedPipe(exe->pipe_error.child_pipe,
|
Ecore_Exe_Event_Data *event_data;
|
||||||
buf, sizeof(buf) - 1, &size, ¤t_size, NULL);
|
|
||||||
if (!res || (size == 0))
|
if (trep->read)
|
||||||
{
|
{
|
||||||
if (exe->close_threads)
|
if (!exe->pipe_read.data_buf)
|
||||||
break;
|
{
|
||||||
|
exe->pipe_read.data_buf = trep->buf;
|
||||||
Sleep(100);
|
exe->pipe_read.data_size = trep->buf_size;
|
||||||
continue;
|
trep->buf = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b = realloc(exe->pipe_read.data_buf,
|
||||||
|
exe->pipe_read.data_size + trep->buf_size);
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
memcpy(b + exe->pipe_read.data_size,
|
||||||
|
trep->buf, trep->buf_size);
|
||||||
|
exe->pipe_read.data_buf = b;
|
||||||
|
exe->pipe_read.data_size += trep->buf_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event_data = ecore_exe_event_data_get(obj, ECORE_EXE_PIPE_READ);
|
||||||
|
if (event_data)
|
||||||
|
{
|
||||||
|
ecore_event_add(ECORE_EXE_EVENT_DATA, event_data,
|
||||||
|
_ecore_exe_event_exe_data_free, NULL);
|
||||||
|
efl_event_callback_call(obj, ECORE_EXE_EVENT_DATA_GET,
|
||||||
|
event_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (trep->error)
|
||||||
current_buf = (char *)malloc(current_size);
|
|
||||||
if (!current_buf)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
res = ReadFile(exe->pipe_error.child_pipe, current_buf, current_size, &size, NULL);
|
|
||||||
if (!res || (size == 0))
|
|
||||||
{
|
{
|
||||||
free(current_buf);
|
if (!exe->pipe_error.data_buf)
|
||||||
current_buf = NULL;
|
{
|
||||||
continue;
|
exe->pipe_error.data_buf = trep->buf;
|
||||||
|
exe->pipe_error.data_size = trep->buf_size;
|
||||||
|
trep->buf = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b = realloc(exe->pipe_error.data_buf,
|
||||||
|
exe->pipe_error.data_size + trep->buf_size);
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
memcpy(b + exe->pipe_error.data_size,
|
||||||
|
trep->buf, trep->buf_size);
|
||||||
|
exe->pipe_error.data_buf = b;
|
||||||
|
exe->pipe_error.data_size += trep->buf_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event_data = ecore_exe_event_data_get(obj, ECORE_EXE_PIPE_ERROR);
|
||||||
|
if (event_data)
|
||||||
|
{
|
||||||
|
ecore_event_add(ECORE_EXE_EVENT_ERROR, event_data,
|
||||||
|
_ecore_exe_event_exe_data_free, NULL);
|
||||||
|
efl_event_callback_call(obj, ECORE_EXE_EVENT_DATA_ERROR,
|
||||||
|
event_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
current_size = size;
|
|
||||||
|
|
||||||
if (!exe->pipe_error.data_buf)
|
|
||||||
{
|
|
||||||
exe->pipe_error.data_buf = current_buf;
|
|
||||||
exe->pipe_error.data_size = current_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exe->pipe_error.data_buf = realloc(exe->pipe_error.data_buf, exe->pipe_error.data_size + current_size);
|
|
||||||
memcpy((unsigned char *)exe->pipe_error.data_buf + exe->pipe_error.data_size, current_buf, current_size);
|
|
||||||
exe->pipe_error.data_size += current_size;
|
|
||||||
free(current_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
event_data = ecore_exe_event_data_get(obj, ECORE_EXE_PIPE_ERROR);
|
|
||||||
if (event_data)
|
|
||||||
{
|
|
||||||
ecore_event_add(ECORE_EXE_EVENT_ERROR, event_data,
|
|
||||||
_ecore_exe_event_exe_data_free,
|
|
||||||
NULL);
|
|
||||||
efl_event_callback_call(obj, ECORE_EXE_EVENT_DATA_ERROR, event_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
current_buf = NULL;
|
|
||||||
current_size = 0;
|
|
||||||
}
|
}
|
||||||
|
free(trep->buf);
|
||||||
_endthreadex(0);
|
free(trep);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD WINAPI
|
static DWORD WINAPI
|
||||||
|
@ -269,54 +279,34 @@ _ecore_exe_enum_windows_procedure(HWND window,
|
||||||
if (CreateRemoteThread(exe->process, NULL, 0,
|
if (CreateRemoteThread(exe->process, NULL, 0,
|
||||||
(LPTHREAD_START_ROUTINE)_ecore_exe_thread_procedure, NULL,
|
(LPTHREAD_START_ROUTINE)_ecore_exe_thread_procedure, NULL,
|
||||||
0, NULL))
|
0, NULL))
|
||||||
{
|
return EINA_FALSE;
|
||||||
printf ("remote thread\n");
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((exe->sig == ECORE_EXE_WIN32_SIGINT) ||
|
if ((exe->sig == ECORE_EXE_WIN32_SIGINT) ||
|
||||||
(exe->sig == ECORE_EXE_WIN32_SIGQUIT))
|
(exe->sig == ECORE_EXE_WIN32_SIGQUIT))
|
||||||
{
|
return EINA_FALSE;
|
||||||
printf ("int or quit\n");
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* WM_CLOSE message */
|
/* WM_CLOSE message */
|
||||||
PostMessage(window, WM_CLOSE, 0, 0);
|
PostMessage(window, WM_CLOSE, 0, 0);
|
||||||
if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0)
|
if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0)
|
||||||
{
|
return EINA_FALSE;
|
||||||
printf ("CLOSE\n");
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* WM_QUIT message */
|
/* WM_QUIT message */
|
||||||
PostMessage(window, WM_QUIT, 0, 0);
|
PostMessage(window, WM_QUIT, 0, 0);
|
||||||
if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0)
|
if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0)
|
||||||
{
|
return EINA_FALSE;
|
||||||
printf ("QUIT\n");
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Exit process */
|
/* Exit process */
|
||||||
if (CreateRemoteThread(exe->process, NULL, 0,
|
if (CreateRemoteThread(exe->process, NULL, 0,
|
||||||
(LPTHREAD_START_ROUTINE)ExitProcess, NULL,
|
(LPTHREAD_START_ROUTINE)ExitProcess, NULL,
|
||||||
0, NULL))
|
0, NULL))
|
||||||
{
|
return EINA_FALSE;
|
||||||
printf ("remote thread 2\n");
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exe->sig == ECORE_EXE_WIN32_SIGTERM)
|
if (exe->sig == ECORE_EXE_WIN32_SIGTERM)
|
||||||
{
|
return EINA_FALSE;
|
||||||
printf ("term\n");
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminateProcess(exe->process, 0);
|
TerminateProcess(exe->process, 0);
|
||||||
|
|
||||||
return EINA_FALSE;
|
return EINA_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,20 +390,16 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe)
|
||||||
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
||||||
|
|
||||||
flags = exe->flags;
|
flags = exe->flags;
|
||||||
|
|
||||||
DBG("Creating process %s with flags %d", exe->cmd, flags);
|
DBG("Creating process %s with flags %d", exe->cmd, flags);
|
||||||
|
|
||||||
if (!exe->cmd) goto error;
|
if (!exe->cmd) goto error;
|
||||||
|
|
||||||
if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR))
|
if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR)) &&
|
||||||
&& (!(flags & ECORE_EXE_PIPE_READ)))
|
(!(flags & ECORE_EXE_PIPE_READ)))
|
||||||
/* We need something to auto pipe. */
|
/* We need something to auto pipe. */
|
||||||
flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR;
|
flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR;
|
||||||
|
|
||||||
if ((flags & ECORE_EXE_USE_SH))
|
if ((flags & ECORE_EXE_USE_SH)) use_sh = EINA_TRUE;
|
||||||
use_sh = EINA_TRUE;
|
else use_sh = eina_str_has_extension(exe->cmd, ".bat");
|
||||||
else
|
|
||||||
use_sh = eina_str_has_extension(exe->cmd, ".bat");
|
|
||||||
|
|
||||||
if (use_sh)
|
if (use_sh)
|
||||||
{
|
{
|
||||||
|
@ -435,45 +421,63 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stdout, stderr and stdin pipes */
|
/* stdout, stderr and stdin pipes */
|
||||||
|
|
||||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
sa.bInheritHandle = EINA_TRUE;
|
sa.bInheritHandle = EINA_TRUE;
|
||||||
sa.lpSecurityDescriptor = NULL;
|
sa.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
/* stdout pipe */
|
if ((exe->flags & ECORE_EXE_PIPE_READ) ||
|
||||||
if (exe->flags & ECORE_EXE_PIPE_READ)
|
(exe->flags & ECORE_EXE_PIPE_ERROR))
|
||||||
{
|
{
|
||||||
if (!CreatePipe(&exe->pipe_read.child_pipe, &child_pipe_read, &sa, 0))
|
Threaddata *tdat;
|
||||||
goto error;
|
|
||||||
if (!SetHandleInformation(exe->pipe_read.child_pipe, HANDLE_FLAG_INHERIT, 0))
|
|
||||||
goto error;
|
|
||||||
exe->pipe_read.thread = (HANDLE)_beginthreadex(NULL, 0,
|
|
||||||
_ecore_exe_pipe_read_thread_cb,
|
|
||||||
obj, 0, NULL);
|
|
||||||
if (!exe->pipe_read.thread)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stderr pipe */
|
tdat = calloc(1, sizeof(Threaddata));
|
||||||
if (exe->flags & ECORE_EXE_PIPE_ERROR)
|
if (tdat)
|
||||||
{
|
{
|
||||||
if (!CreatePipe(&exe->pipe_error.child_pipe, &child_pipe_error, &sa, 0))
|
tdat->obj = obj;
|
||||||
goto error;
|
/* stdout pipe */
|
||||||
if (!SetHandleInformation(exe->pipe_error.child_pipe, HANDLE_FLAG_INHERIT, 0))
|
if (exe->flags & ECORE_EXE_PIPE_READ)
|
||||||
goto error;
|
{
|
||||||
exe->pipe_error.thread = (HANDLE)_beginthreadex(NULL, 0,
|
if (!CreatePipe(&exe->pipe_read.child_pipe,
|
||||||
_ecore_exe_pipe_error_thread_cb,
|
&child_pipe_read, &sa, 0))
|
||||||
obj, 0, NULL);
|
goto error;
|
||||||
if (!exe->pipe_error.thread)
|
if (!SetHandleInformation(exe->pipe_read.child_pipe,
|
||||||
goto error;
|
HANDLE_FLAG_INHERIT, 0))
|
||||||
|
goto error;
|
||||||
|
tdat->read = EINA_TRUE;
|
||||||
|
tdat->read_pipe = exe->pipe_read.child_pipe;
|
||||||
|
}
|
||||||
|
/* stderr pipe */
|
||||||
|
if (exe->flags & ECORE_EXE_PIPE_ERROR)
|
||||||
|
{
|
||||||
|
if (!CreatePipe(&exe->pipe_error.child_pipe,
|
||||||
|
&child_pipe_error, &sa, 0))
|
||||||
|
goto error;
|
||||||
|
if (!SetHandleInformation(exe->pipe_error.child_pipe,
|
||||||
|
HANDLE_FLAG_INHERIT, 0))
|
||||||
|
goto error;
|
||||||
|
tdat->error = EINA_TRUE;
|
||||||
|
tdat->error_pipe = exe->pipe_error.child_pipe;
|
||||||
|
}
|
||||||
|
exe->th = ecore_thread_feedback_run
|
||||||
|
(_ecore_exe_win32_io_poll_thread,
|
||||||
|
_ecore_exe_win32_io_poll_notify,
|
||||||
|
NULL, NULL, tdat, EINA_TRUE);
|
||||||
|
if (!exe->th)
|
||||||
|
{
|
||||||
|
free(tdat);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stdin pipe */
|
/* stdin pipe */
|
||||||
if (exe->flags & ECORE_EXE_PIPE_WRITE)
|
if (exe->flags & ECORE_EXE_PIPE_WRITE)
|
||||||
{
|
{
|
||||||
if (!CreatePipe(&exe->pipe_write.child_pipe, &exe->pipe_write.child_pipe_x, &sa, 0))
|
if (!CreatePipe(&exe->pipe_write.child_pipe,
|
||||||
|
&exe->pipe_write.child_pipe_x, &sa, 0))
|
||||||
goto error;
|
goto error;
|
||||||
if (!SetHandleInformation(exe->pipe_write.child_pipe_x, HANDLE_FLAG_INHERIT, 0))
|
if (!SetHandleInformation(exe->pipe_write.child_pipe_x,
|
||||||
|
HANDLE_FLAG_INHERIT, 0))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,14 +498,14 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe)
|
||||||
{
|
{
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
msg = evil_last_error_get();
|
msg = evil_last_error_get();
|
||||||
if (msg)
|
if (msg)
|
||||||
{
|
{
|
||||||
WRN("Failed to create process %s: %s", exe_cmd_buf, msg);
|
WRN("Failed to create process %s: %s", exe_cmd_buf, msg);
|
||||||
free(msg);
|
free(msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
WRN("Failed to create process %s: %ld", exe_cmd_buf, GetLastError());
|
WRN("Failed to create process %s: %ld", exe_cmd_buf, GetLastError());
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,7 +523,6 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe)
|
||||||
/* FIXME: This does not work if the child is an EFL-based app */
|
/* FIXME: This does not work if the child is an EFL-based app */
|
||||||
/* if (WaitForInputIdle(pi.hProcess, INFINITE) == WAIT_FAILED) */
|
/* if (WaitForInputIdle(pi.hProcess, INFINITE) == WAIT_FAILED) */
|
||||||
/* goto error; */
|
/* goto error; */
|
||||||
|
|
||||||
exe->process = pi.hProcess;
|
exe->process = pi.hProcess;
|
||||||
exe->process_thread = pi.hThread;
|
exe->process_thread = pi.hThread;
|
||||||
exe->pid = pi.dwProcessId;
|
exe->pid = pi.dwProcessId;
|
||||||
|
@ -527,8 +530,7 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe)
|
||||||
|
|
||||||
exe->h_close = ecore_main_win32_handler_add(exe->process,
|
exe->h_close = ecore_main_win32_handler_add(exe->process,
|
||||||
_ecore_exe_close_cb, obj);
|
_ecore_exe_close_cb, obj);
|
||||||
if (!exe->h_close)
|
if (!exe->h_close) goto error;
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (ResumeThread(exe->process_thread) == ((DWORD)-1))
|
if (ResumeThread(exe->process_thread) == ((DWORD)-1))
|
||||||
{
|
{
|
||||||
|
@ -538,14 +540,10 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe)
|
||||||
|
|
||||||
_ecore_exe_exes = eina_list_append(_ecore_exe_exes, obj);
|
_ecore_exe_exes = eina_list_append(_ecore_exe_exes, obj);
|
||||||
|
|
||||||
e = (Ecore_Exe_Event_Add *)calloc(1, sizeof(Ecore_Exe_Event_Add));
|
e = calloc(1, sizeof(Ecore_Exe_Event_Add));
|
||||||
if (!e) goto error;
|
if (!e) goto error;
|
||||||
|
|
||||||
e->exe = obj;
|
e->exe = obj;
|
||||||
|
ecore_event_add(ECORE_EXE_EVENT_ADD, e, _ecore_exe_event_add_free, NULL);
|
||||||
ecore_event_add(ECORE_EXE_EVENT_ADD, e,
|
|
||||||
_ecore_exe_event_add_free, NULL);
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -554,9 +552,9 @@ error:
|
||||||
|
|
||||||
Eina_Bool
|
Eina_Bool
|
||||||
_impl_ecore_exe_send(Ecore_Exe *obj,
|
_impl_ecore_exe_send(Ecore_Exe *obj,
|
||||||
Ecore_Exe_Data *exe,
|
Ecore_Exe_Data *exe,
|
||||||
const void *data,
|
const void *data,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
DWORD num_exe;
|
DWORD num_exe;
|
||||||
|
@ -570,7 +568,6 @@ _impl_ecore_exe_send(Ecore_Exe *obj,
|
||||||
exe->pipe_write.data_size += size;
|
exe->pipe_write.data_size += size;
|
||||||
|
|
||||||
res = WriteFile(exe->pipe_write.child_pipe_x, buf, exe->pipe_write.data_size, &num_exe, NULL);
|
res = WriteFile(exe->pipe_write.child_pipe_x, buf, exe->pipe_write.data_size, &num_exe, NULL);
|
||||||
printf(" ** res : %d\n", res);
|
|
||||||
if (!res || num_exe == 0)
|
if (!res || num_exe == 0)
|
||||||
{
|
{
|
||||||
ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p",
|
ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p",
|
||||||
|
@ -583,8 +580,8 @@ _impl_ecore_exe_send(Ecore_Exe *obj,
|
||||||
|
|
||||||
Ecore_Exe_Event_Data *
|
Ecore_Exe_Event_Data *
|
||||||
_impl_ecore_exe_event_data_get(Ecore_Exe *obj,
|
_impl_ecore_exe_event_data_get(Ecore_Exe *obj,
|
||||||
Ecore_Exe_Data *exe,
|
Ecore_Exe_Data *exe,
|
||||||
Ecore_Exe_Flags flags)
|
Ecore_Exe_Flags flags)
|
||||||
{
|
{
|
||||||
Ecore_Exe_Event_Data *e = NULL;
|
Ecore_Exe_Event_Data *e = NULL;
|
||||||
unsigned char *inbuf;
|
unsigned char *inbuf;
|
||||||
|
@ -593,103 +590,102 @@ _impl_ecore_exe_event_data_get(Ecore_Exe *obj,
|
||||||
|
|
||||||
/* Sort out what sort of event we are. */
|
/* Sort out what sort of event we are. */
|
||||||
if (flags & ECORE_EXE_PIPE_READ)
|
if (flags & ECORE_EXE_PIPE_READ)
|
||||||
{
|
{
|
||||||
flags = ECORE_EXE_PIPE_READ;
|
flags = ECORE_EXE_PIPE_READ;
|
||||||
if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED)
|
if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED)
|
||||||
is_buffered = EINA_TRUE;
|
is_buffered = EINA_TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flags = ECORE_EXE_PIPE_ERROR;
|
flags = ECORE_EXE_PIPE_ERROR;
|
||||||
if (exe->flags & ECORE_EXE_PIPE_ERROR_LINE_BUFFERED)
|
if (exe->flags & ECORE_EXE_PIPE_ERROR_LINE_BUFFERED)
|
||||||
is_buffered = EINA_TRUE;
|
is_buffered = EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the data. */
|
/* Get the data. */
|
||||||
if (flags & ECORE_EXE_PIPE_READ)
|
if (flags & ECORE_EXE_PIPE_READ)
|
||||||
{
|
{
|
||||||
inbuf = exe->pipe_read.data_buf;
|
inbuf = exe->pipe_read.data_buf;
|
||||||
inbuf_num = exe->pipe_read.data_size;
|
inbuf_num = exe->pipe_read.data_size;
|
||||||
exe->pipe_read.data_buf = NULL;
|
exe->pipe_read.data_buf = NULL;
|
||||||
exe->pipe_read.data_size = 0;
|
exe->pipe_read.data_size = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inbuf = exe->pipe_error.data_buf;
|
inbuf = exe->pipe_error.data_buf;
|
||||||
inbuf_num = exe->pipe_error.data_size;
|
inbuf_num = exe->pipe_error.data_size;
|
||||||
exe->pipe_error.data_buf = NULL;
|
exe->pipe_error.data_buf = NULL;
|
||||||
exe->pipe_error.data_size = 0;
|
exe->pipe_error.data_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = calloc(1, sizeof(Ecore_Exe_Event_Data));
|
e = calloc(1, sizeof(Ecore_Exe_Event_Data));
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
e->exe = obj;
|
e->exe = obj;
|
||||||
e->data = inbuf;
|
e->data = inbuf;
|
||||||
e->size = inbuf_num;
|
e->size = inbuf_num;
|
||||||
|
|
||||||
if (is_buffered) /* Deal with line buffering. */
|
if (is_buffered) /* Deal with line buffering. */
|
||||||
{
|
{
|
||||||
char *c;
|
char *c;
|
||||||
DWORD i;
|
DWORD i;
|
||||||
DWORD max = 0;
|
DWORD max = 0;
|
||||||
DWORD count = 0;
|
DWORD count = 0;
|
||||||
DWORD last = 0;
|
DWORD last = 0;
|
||||||
|
|
||||||
c = (char *)inbuf;
|
c = (char *)inbuf;
|
||||||
for (i = 0; i < inbuf_num; i++)
|
for (i = 0; i < inbuf_num; i++)
|
||||||
{
|
{
|
||||||
if (inbuf[i] == '\n')
|
if (inbuf[i] == '\n')
|
||||||
{
|
{
|
||||||
int end;
|
int end;
|
||||||
|
|
||||||
if (count >= max)
|
if (count >= max)
|
||||||
{
|
{
|
||||||
max += 10;
|
max += 10;
|
||||||
e->lines = realloc(e->lines, sizeof(Ecore_Exe_Event_Data_Line) * (max + 1));
|
e->lines = realloc
|
||||||
}
|
(e->lines,
|
||||||
|
sizeof(Ecore_Exe_Event_Data_Line) * (max + 1));
|
||||||
if ((i >= 1) && (inbuf[i - 1] == '\r'))
|
}
|
||||||
end = i - 1;
|
|
||||||
else
|
|
||||||
end = i;
|
|
||||||
inbuf[end] = '\0';
|
|
||||||
e->lines[count].line = c;
|
|
||||||
e->lines[count].size = end - last;
|
|
||||||
last = i + 1;
|
|
||||||
c = (char *)&inbuf[last];
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i > last) /* Partial line left over, save it for next time. */
|
|
||||||
{
|
|
||||||
if (count != 0) e->size = last;
|
|
||||||
if (flags & ECORE_EXE_PIPE_READ)
|
|
||||||
{
|
|
||||||
exe->pipe_read.data_size = i - last;
|
|
||||||
exe->pipe_read.data_buf = malloc(exe->pipe_read.data_size);
|
|
||||||
memcpy(exe->pipe_read.data_buf, c, exe->pipe_read.data_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exe->pipe_error.data_size = i - last;
|
|
||||||
exe->pipe_error.data_buf = malloc(exe->pipe_error.data_size);
|
|
||||||
memcpy(exe->pipe_error.data_buf, c, exe->pipe_error.data_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count == 0) /* No lines to send, cancel the event. */
|
|
||||||
{
|
|
||||||
_ecore_exe_event_exe_data_free(NULL, e);
|
|
||||||
e = NULL;
|
|
||||||
}
|
|
||||||
else /* NULL terminate the array, so that people know where the end is. */
|
|
||||||
{
|
|
||||||
e->lines[count].line = NULL;
|
|
||||||
e->lines[count].size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ((i >= 1) && (inbuf[i - 1] == '\r')) end = i - 1;
|
||||||
|
else end = i;
|
||||||
|
inbuf[end] = '\0';
|
||||||
|
e->lines[count].line = c;
|
||||||
|
e->lines[count].size = end - last;
|
||||||
|
last = i + 1;
|
||||||
|
c = (char *)&inbuf[last];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i > last) /* Partial line left over, save it for next time. */
|
||||||
|
{
|
||||||
|
if (count != 0) e->size = last;
|
||||||
|
if (flags & ECORE_EXE_PIPE_READ)
|
||||||
|
{
|
||||||
|
exe->pipe_read.data_size = i - last;
|
||||||
|
exe->pipe_read.data_buf = malloc(exe->pipe_read.data_size);
|
||||||
|
memcpy(exe->pipe_read.data_buf, c, exe->pipe_read.data_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exe->pipe_error.data_size = i - last;
|
||||||
|
exe->pipe_error.data_buf = malloc(exe->pipe_error.data_size);
|
||||||
|
memcpy(exe->pipe_error.data_buf, c, exe->pipe_error.data_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count == 0) /* No lines to send, cancel the event. */
|
||||||
|
{
|
||||||
|
_ecore_exe_event_exe_data_free(NULL, e);
|
||||||
|
e = NULL;
|
||||||
|
}
|
||||||
|
else /* NULL terminate the array, so that people know where the end is. */
|
||||||
|
{
|
||||||
|
e->lines[count].line = NULL;
|
||||||
|
e->lines[count].size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,8 +697,7 @@ _impl_ecore_exe_efl_object_destructor(Eo *obj, Ecore_Exe_Data *exe)
|
||||||
_ecore_exe_threads_terminate(obj);
|
_ecore_exe_threads_terminate(obj);
|
||||||
|
|
||||||
data = exe->data;
|
data = exe->data;
|
||||||
if (exe->pre_free_cb)
|
if (exe->pre_free_cb) exe->pre_free_cb(data, obj);
|
||||||
exe->pre_free_cb(data, obj);
|
|
||||||
|
|
||||||
IF_FN_DEL(ecore_main_win32_handler_del, exe->h_close);
|
IF_FN_DEL(ecore_main_win32_handler_del, exe->h_close);
|
||||||
|
|
||||||
|
@ -722,21 +717,15 @@ _impl_ecore_exe_efl_object_destructor(Eo *obj, Ecore_Exe_Data *exe)
|
||||||
void
|
void
|
||||||
_impl_ecore_exe_pause(Ecore_Exe *obj EINA_UNUSED, Ecore_Exe_Data *exe)
|
_impl_ecore_exe_pause(Ecore_Exe *obj EINA_UNUSED, Ecore_Exe_Data *exe)
|
||||||
{
|
{
|
||||||
if (exe->is_suspended)
|
if (exe->is_suspended) return;
|
||||||
return;
|
if (SuspendThread(exe->process_thread) != (DWORD)-1) exe->is_suspended = 1;
|
||||||
|
|
||||||
if (SuspendThread(exe->process_thread) != (DWORD)-1)
|
|
||||||
exe->is_suspended = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_impl_ecore_exe_continue(Ecore_Exe *obj EINA_UNUSED, Ecore_Exe_Data *exe)
|
_impl_ecore_exe_continue(Ecore_Exe *obj EINA_UNUSED, Ecore_Exe_Data *exe)
|
||||||
{
|
{
|
||||||
if (!exe->is_suspended)
|
if (!exe->is_suspended) return;
|
||||||
return;
|
if (ResumeThread(exe->process_thread) != (DWORD)-1) exe->is_suspended = 0;
|
||||||
|
|
||||||
if (ResumeThread(exe->process_thread) != (DWORD)-1)
|
|
||||||
exe->is_suspended = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -768,7 +757,7 @@ _impl_ecore_exe_terminate(Ecore_Exe *obj, Ecore_Exe_Data *exe)
|
||||||
CloseHandle(exe->process);
|
CloseHandle(exe->process);
|
||||||
exe->process = NULL;
|
exe->process = NULL;
|
||||||
exe->sig = ECORE_EXE_WIN32_SIGTERM;
|
exe->sig = ECORE_EXE_WIN32_SIGTERM;
|
||||||
while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)obj)) ;
|
while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -779,31 +768,31 @@ _impl_ecore_exe_kill(Ecore_Exe *obj, Ecore_Exe_Data *exe)
|
||||||
CloseHandle(exe->process);
|
CloseHandle(exe->process);
|
||||||
exe->process = NULL;
|
exe->process = NULL;
|
||||||
exe->sig = ECORE_EXE_WIN32_SIGKILL;
|
exe->sig = ECORE_EXE_WIN32_SIGKILL;
|
||||||
while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)obj)) ;
|
while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_impl_ecore_exe_auto_limits_set(Ecore_Exe *obj EINA_UNUSED,
|
_impl_ecore_exe_auto_limits_set(Ecore_Exe *obj EINA_UNUSED,
|
||||||
Ecore_Exe_Data *exe EINA_UNUSED,
|
Ecore_Exe_Data *exe EINA_UNUSED,
|
||||||
int start_bytes EINA_UNUSED,
|
int start_bytes EINA_UNUSED,
|
||||||
int end_bytes EINA_UNUSED,
|
int end_bytes EINA_UNUSED,
|
||||||
int start_lines EINA_UNUSED,
|
int start_lines EINA_UNUSED,
|
||||||
int end_lines EINA_UNUSED)
|
int end_lines EINA_UNUSED)
|
||||||
{
|
{
|
||||||
ERR("Not implemented on windows!");
|
ERR("Not implemented on windows!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_impl_ecore_exe_signal(Ecore_Exe *obj EINA_UNUSED,
|
_impl_ecore_exe_signal(Ecore_Exe *obj EINA_UNUSED,
|
||||||
Ecore_Exe_Data *exe EINA_UNUSED,
|
Ecore_Exe_Data *exe EINA_UNUSED,
|
||||||
int num EINA_UNUSED)
|
int num EINA_UNUSED)
|
||||||
{
|
{
|
||||||
ERR("Not implemented on windows!");
|
ERR("Not implemented on windows!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_impl_ecore_exe_hup(Ecore_Exe *obj EINA_UNUSED,
|
_impl_ecore_exe_hup(Ecore_Exe *obj EINA_UNUSED,
|
||||||
Ecore_Exe_Data *exe EINA_UNUSED)
|
Ecore_Exe_Data *exe EINA_UNUSED)
|
||||||
{
|
{
|
||||||
ERR("Not implemented on windows!");
|
ERR("Not implemented on windows!");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue