lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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