[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: os.execute and the dreaded Windows console
- From: "Robert Raschke" <rtrlists@...>
- Date: Tue, 9 Sep 2008 09:33:49 +0100
I've been using the follwoing functions. They include the ability to
kill a process as well as wait for completion. I register these with
the names spawn, kill and waitfor.
Spawn takes a command line to execute and returns a process handle as
a userdata. returns nil and error if it fails.
Kill takes a process handle, tries to stop the associated process.
Returns an error if it fails.
Waitfor takes a process handle and waits for the process to finish.
Optionally you can give a timeout value in milliseconds. If the
process exits, it returns "exit" plus the exit code of the process. If
you've given a timeout value and the process has not exited within
that time you get "timeout". Otherwise you get nil and an error
message.
typedef struct {
HANDLE hProcess;
HANDLE hThread;
} process_t;
static void
push_last_error(lua_State *L)
{
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL);
lua_pushstring(L, lpMsgBuf);
LocalFree(lpMsgBuf);
}
static int
lspawn(lua_State *L)
{
int n = lua_gettop(L); /* number of arguments */
if (n != 1) {
lua_pushstring(L, "wrong number of arguments to function `spawn'");
lua_error(L);
} else {
/* Inspired by MSDN
ms-help://MS.MSDN.vAug06.en/dllproc/base/creating_processes.htm */
STARTUPINFO si;
PROCESS_INFORMATION pi;
LPTSTR szCmdline = lua_tostring(L, 1);
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (! CreateProcess(NULL, szCmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
NULL, NULL, &si, &pi)) {
lua_pushnil(L);
push_last_error(L);
return 2;
} else {
process_t *p = (process_t *) lua_newuserdata(L, sizeof(process_t));
p->hProcess = pi.hProcess;
p->hThread = pi.hThread;
return 1;
}
}
return 0;
}
static int
lkill(lua_State *L)
{
int n = lua_gettop(L); /* number of arguments */
if (n != 1) {
lua_pushstring(L, "wrong number of arguments to function `kill'");
lua_error(L);
} else {
process_t *p = (process_t *) lua_touserdata(L, 1);
luaL_argcheck(L, p != NULL, 1, "'process handle' expected");
if (! TerminateProcess(p->hProcess, 0)) {
push_last_error(L);
return 1;
} else {
CloseHandle(p->hProcess);
CloseHandle(p->hThread);
free(p);
return 0;
}
}
return 0;
}
static int
lwaitfor(lua_State *L)
{
int n = lua_gettop(L); /* number of arguments */
if (n != 1 && n != 2) {
lua_pushstring(L, "wrong number of arguments to function `waitfor'");
lua_error(L);
} else {
process_t *p = (process_t *) lua_touserdata(L, 1);
DWORD millis = INFINITE;
luaL_argcheck(L, p != NULL, 1, "'process handle' expected");
if (n == 2) {
lua_Number i = lua_tonumber(L, 2);
luaL_argcheck(L, i >= 0 && i < INT_MAX, 1, "'milliseconds' expected");
millis = i;
}
switch (WaitForSingleObject(p->hProcess, millis)) {
default:
lua_pushnil(L);
push_last_error(L);
return 2;
case WAIT_TIMEOUT:
lua_pushstring(L, "timeout");
return 1;
case WAIT_OBJECT_0: {
DWORD code;
if (! GetExitCodeProcess(p->hProcess, &code)) {
lua_pushnil(L);
push_last_error(L);
return 2;
} else {
lua_pushstring(L, "exit");
lua_pushnumber(L, code);
CloseHandle(p->hProcess);
CloseHandle(p->hThread);
free(p);
return 2;
}
}
}
}
return 0;
}
Robby