//build@ gcc -shared -o spawner-ex.dll -I..\..\lua\include win32-spawner-ex.c scite.la 
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <process.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <ctype.h>

#include "ComLog.h"

#define lua_c

#include "lprefix.h"


#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LUA_COMPAT_5_1
#ifdef __cplusplus
extern "C" {
#include "lua.h"

#include "lauxlib.h"
#include "lualib.h"
extern LUA_API size_t AnsicFromutf8 (const char *s, int len, char *to);
extern LUA_API size_t Utf8FromAnsic (const char *s, int len, char *to);

}
#endif
#include "LuaDll.h"

#if !defined(LUA_PROMPT)
#define LUA_PROMPT		"> "
#define LUA_PROMPT2		">> "
#endif

#if !defined(LUA_PROGNAME)
#define LUA_PROGNAME		"lua"
#endif

#if !defined(LUA_MAXINPUT)
#define LUA_MAXINPUT		512
#endif

#if !defined(LUA_INIT_VAR)
#define LUA_INIT_VAR		"LUA_INIT"
#endif

#define LUA_INITVARVERSION	LUA_INIT_VAR LUA_VERSUFFIX


/*
** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
** is, whether we're running lua interactively).
*/
#if !defined(lua_stdin_is_tty)	/* { */

#if defined(LUA_USE_POSIX)	/* { */

#include <unistd.h>
#define lua_stdin_is_tty()	isatty(0)

#elif defined(LUA_USE_WINDOWS)	/* }{ */

#include <io.h>
#include <windows.h>

#define lua_stdin_is_tty()	_isatty(_fileno(stdin))

#else				/* }{ */

/* ISO C definition */
#define lua_stdin_is_tty()	1  /* assume stdin is a tty */

#endif				/* } */

#endif				/* } */


/*
** lua_readline defines how to show a prompt and then read a line from
** the standard input.
** lua_saveline defines how to "save" a read line in a "history".
** lua_freeline defines how to free a line read by lua_readline.
*/
#if !defined(lua_readline)	/* { */

#if defined(LUA_USE_READLINE)	/* { */

#include <readline/readline.h>
#include <readline/history.h>
#define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL)
#define lua_saveline(L,line)	((void)L, add_history(line))
#define lua_freeline(L,b)	((void)L, free(b))

#else				/* }{ */

#define lua_readline(L,b,p) \
        ((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \
        fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */
#define lua_saveline(L,line)	{ (void)L; (void)line; }
#define lua_freeline(L,b)	{ (void)L; (void)b; }

#endif				/* } */

#endif				/* } */




static lua_State *globalL = NULL;

static const char *progname = LUA_PROGNAME;


/*
** Hook set by signal function to stop the interpreter.
*/
static void lstop (lua_State *L, lua_Debug *ar) {
  (void)ar;  /* unused arg. */
  lua_sethook(L, NULL, 0, 0);  /* reset hook */
  luaL_error(L, "interrupted!");
}


/*
** Function to be called at a C signal. Because a C signal cannot
** just change a Lua state (as there is no proper synchronization),
** this function only sets a hook that, when called, will stop the
** interpreter.
*/
static void laction (int i) {
  signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
  lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
}


static void print_usage (const char *badoption) {
  lua_writestringerror("%s: ", progname);
  if (badoption[1] == 'e' || badoption[1] == 'l')
    lua_writestringerror("'%s' needs argument\n", badoption);
  else
    lua_writestringerror("unrecognized option '%s'\n", badoption);
  lua_writestringerror(
  "usage: %s [options] [script [args]]\n"
  "Available options are:\n"
  "  -e stat  execute string 'stat'\n"
  "  -i       enter interactive mode after executing 'script'\n"
  "  -l name  require library 'name'\n"
  "  -v       show version information\n"
  "  -E       ignore environment variables\n"
  "  --       stop handling options\n"
  "  -        stop handling options and execute stdin\n"
  ,
  progname);
}


/*
** Prints an error message, adding the program name in front of it
** (if present)
*/
static void l_message (const char *pname, const char *msg) {
  if (pname) lua_writestringerror("%s: ", pname);
  lua_writestringerror("%s\n", msg);
}


/*
** Check whether 'status' is not OK and, if so, prints the error
** message on the top of the stack. It assumes that the error object
** is a string, as it was either generated by Lua or by 'msghandler'.
*/
static int report (lua_State *L, int status) {
  if (status != LUA_OK) {
    const char *msg = lua_tostring(L, -1);
    l_message(progname, msg);
    lua_pop(L, 1);  /* remove message */
  }
  return status;
}


/*
** Message handler used to run all chunks
*/
static int msghandler (lua_State *L) {
  const char *msg = lua_tostring(L, 1);
  if (msg == NULL) {  /* is error object not a string? */
    if (luaL_callmeta(L, 1, "__tostring") &&  /* does it have a metamethod */
        lua_type(L, -1) == LUA_TSTRING)  /* that produces a string? */
      return 1;  /* that is the message */
    else
      msg = lua_pushfstring(L, "(error object is a %s value)",
                               luaL_typename(L, 1));
  }
  luaL_traceback(L, L, msg, 1);  /* append a standard traceback */
  return 1;  /* return the traceback */
}


/*
** Interface to 'lua_pcall', which sets appropriate message function
** and C-signal handler. Used to run all chunks.
*/
static int docall (lua_State *L, int narg, int nres) {
  int status;
  int base = lua_gettop(L) - narg;  /* function index */
  lua_pushcfunction(L, msghandler);  /* push message handler */
  lua_insert(L, base);  /* put it under function and args */
  globalL = L;  /* to be available to 'laction' */
  signal(SIGINT, laction);  /* set C-signal handler */
  status = lua_pcall(L, narg, nres, base);
  signal(SIGINT, SIG_DFL); /* reset C-signal handler */
  lua_remove(L, base);  /* remove message handler from the stack */
  return status;
}


static void print_version (void) {
  lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
  lua_writeline();
}


/*
** Create the 'arg' table, which stores all arguments from the
** command line ('argv'). It should be aligned so that, at index 0,
** it has 'argv[script]', which is the script name. The arguments
** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base.
*/
static void createargtable (lua_State *L, char **argv, int argc, int script) {
  int i, narg;
  if (script == argc) script = 0;  /* no script name? */
  narg = argc - (script + 1);  /* number of positive indices */
  lua_createtable(L, narg, script + 1);
  for (i = 0; i < argc; i++) {
    lua_pushstring(L, argv[i]);
    lua_rawseti(L, -2, i - script);
  }
  lua_setglobal(L, "arg");
}


static int dochunk (lua_State *L, int status) {
  if (status == LUA_OK) status = docall(L, 0, 0);
  return report(L, status);
}


static int dofile (lua_State *L, const char *name) {
  return dochunk(L, luaL_loadfile(L, name));
}


static int dostring (lua_State *L, const char *s, const char *name) {
  return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name));
}


/*
** Calls 'require(name)' and stores the result in a global variable
** with the given name.
*/
static int dolibrary (lua_State *L, const char *name) {
  int status;
  lua_getglobal(L, "require");
  lua_pushstring(L, name);
  status = docall(L, 1, 1);  /* call 'require(name)' */
  if (status == LUA_OK)
    lua_setglobal(L, name);  /* global[name] = require return */
  return report(L, status);
}


/*
** Returns the string to be used as a prompt by the interpreter.
*/
static const char *get_prompt (lua_State *L, int firstline) {
  const char *p;
  lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
  p = lua_tostring(L, -1);
  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
  return p;
}

/* mark in error messages for incomplete statements */
#define EOFMARK		"<eof>"
#define marklen		(sizeof(EOFMARK)/sizeof(char) - 1)


/*
** Check whether 'status' signals a syntax error and the error
** message at the top of the stack ends with the above mark for
** incomplete statements.
*/
static int incomplete (lua_State *L, int status) {
  if (status == LUA_ERRSYNTAX) {
    size_t lmsg;
    const char *msg = lua_tolstring(L, -1, &lmsg);
    if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) {
      lua_pop(L, 1);
      return 1;
    }
  }
  return 0;  /* else... */
}


/*
** Prompt the user, read a line, and push it into the Lua stack.
*/
static int pushline (lua_State *L, int firstline) {
  char buffer[LUA_MAXINPUT];
  char *b = buffer;
  size_t l;
  const char *prmt = get_prompt(L, firstline);
  int readstatus = lua_readline(L, b, prmt);
  if (readstatus == 0)
    return 0;  /* no input (prompt will be popped by caller) */
  lua_pop(L, 1);  /* remove prompt */
  l = strlen(b);
  if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
    b[--l] = '\0';  /* remove it */
   if (firstline && (strcmp("exit", b) == 0 || strcmp("quit", b) == 0)) {
	  return 0;
  }
  if (firstline && b[0] == '=')  /* for compatibility with 5.2, ... */
    lua_pushfstring(L, "return %s", b + 1);  /* change '=' to 'return' */
  else
    lua_pushlstring(L, b, l);
  lua_freeline(L, b);
  return 1;
}


/*
** Try to compile line on the stack as 'return <line>;'; on return, stack
** has either compiled chunk or original line (if compilation failed).
*/
static int addreturn (lua_State *L) {
  const char *line = lua_tostring(L, -1);  /* original line */
  const char *retline = lua_pushfstring(L, "return %s;", line);
  int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
  if (status == LUA_OK) {
    lua_remove(L, -2);  /* remove modified line */
    if (line[0] != '\0')  /* non empty? */
      lua_saveline(L, line);  /* keep history */
  }
  else
    lua_pop(L, 2);  /* pop result from 'luaL_loadbuffer' and modified line */
  return status;
}


/*
** Read multiple lines until a complete Lua statement
*/
static int multiline (lua_State *L) {
  for (;;) {  /* repeat until gets a complete statement */
    size_t len;
    const char *line = lua_tolstring(L, 1, &len);  /* get what it has */
    int status = luaL_loadbuffer(L, line, len, "=stdin");  /* try it */
    if (!incomplete(L, status) || !pushline(L, 0)) {
      lua_saveline(L, line);  /* keep history */
      return status;  /* cannot or should not try to add continuation line */
    }
    lua_pushliteral(L, "\n");  /* add newline... */
    lua_insert(L, -2);  /* ...between the two lines */
    lua_concat(L, 3);  /* join them */
  }
}


/*
** Read a line and try to load (compile) it first as an expression (by
** adding "return " in front of it) and second as a statement. Return
** the final status of load/call with the resulting function (if any)
** in the top of the stack.
*/
static int loadline (lua_State *L) {
  int status;
  lua_settop(L, 0);
  if (!pushline(L, 1))
    return -1;  /* no input */
  if ((status = addreturn(L)) != LUA_OK)  /* 'return ...' did not work? */
    status = multiline(L);  /* try as command, maybe with continuation lines */
  lua_remove(L, 1);  /* remove line from the stack */
  lua_assert(lua_gettop(L) == 1);
  return status;
}


/*
** Prints (calling the Lua 'print' function) any values on the stack
*/
static void l_print (lua_State *L) {
  int n = lua_gettop(L);
  if (n > 0) {  /* any result to be printed? */
    luaL_checkstack(L, LUA_MINSTACK, "too many results to print");
    lua_getglobal(L, "print");
    lua_insert(L, 1);
    if (lua_pcall(L, n, 0, 0) != LUA_OK)
      l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)",
                                             lua_tostring(L, -1)));
  }
}


/*
** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and
** print any results.
*/
static void doREPL (lua_State *L) {
  int status;
  const char *oldprogname = progname;
  progname = NULL;  /* no 'progname' on errors in interactive mode */
  while ((status = loadline(L)) != -1) {
    if (status == LUA_OK)
      status = docall(L, 0, LUA_MULTRET);
    if (status == LUA_OK) l_print(L);
    else report(L, status);
  }
  lua_settop(L, 0);  /* clear stack */
  lua_writeline();
  progname = oldprogname;
}


/*
** Push on the stack the contents of table 'arg' from 1 to #arg
*/
static int pushargs (lua_State *L) {
  int i, n;
  if (lua_getglobal(L, "arg") != LUA_TTABLE)
    luaL_error(L, "'arg' is not a table");
  n = (int)luaL_len(L, -1);
  luaL_checkstack(L, n + 3, "too many arguments to script");
  for (i = 1; i <= n; i++)
    lua_rawgeti(L, -i, i);
  lua_remove(L, -i);  /* remove table from the stack */
  return n;
}


static int handle_script (lua_State *L, char **argv) {
  int status;
  const char *fname = argv[0];
  if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
    fname = NULL;  /* stdin */
  status = luaL_loadfile(L, fname);
  if (status == LUA_OK) {
    int n = pushargs(L);  /* push arguments to script */
    status = docall(L, n, LUA_MULTRET);
  }
  return report(L, status);
}



/* bits of various argument indicators in 'args' */
#define has_error	1	/* bad option */
#define has_i		2	/* -i */
#define has_v		4	/* -v */
#define has_e		8	/* -e */
#define has_E		16	/* -E */

/*
** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds
** any invalid argument). 'first' returns the first not-handled argument
** (either the script name or a bad argument in case of error).
*/
static int collectargs (char **argv, int *first) {
  int args = 0;
  int i;
  for (i = 1; argv[i] != NULL; i++) {
    *first = i;
    if (argv[i][0] != '-')  /* not an option? */
        return args;  /* stop handling options */
    switch (argv[i][1]) {  /* else check option */
      case '-':  /* '--' */
        if (argv[i][2] != '\0')  /* extra characters after '--'? */
          return has_error;  /* invalid option */
        *first = i + 1;
        return args;
      case '\0':  /* '-' */
        return args;  /* script "name" is '-' */
      case 'E':
        if (argv[i][2] != '\0')  /* extra characters after 1st? */
          return has_error;  /* invalid option */
        args |= has_E;
        break;
      case 'i':
        args |= has_i;  /* (-i implies -v) *//* FALLTHROUGH */
      case 'v':
        if (argv[i][2] != '\0')  /* extra characters after 1st? */
          return has_error;  /* invalid option */
        args |= has_v;
        break;
      case 'e':
        args |= has_e;  /* FALLTHROUGH */
      case 'l':  /* both options need an argument */
        if (argv[i][2] == '\0') {  /* no concatenated argument? */
          i++;  /* try next 'argv' */
          if (argv[i] == NULL || argv[i][0] == '-')
            return has_error;  /* no next argument or it is another option */
        }
        break;
      default:  /* invalid option */
        return has_error;
    }
  }
  *first = i;  /* no script name */
  return args;
}


/*
** Processes options 'e' and 'l', which involve running Lua code.
** Returns 0 if some code raises an error.
*/
static int runargs (lua_State *L, char **argv, int n) {
  int i;
  for (i = 1; i < n; i++) {
    int option = argv[i][1];
    lua_assert(argv[i][0] == '-');  /* already checked */
    if (option == 'e' || option == 'l') {
      int status;
      const char *extra = argv[i] + 2;  /* both options need an argument */
      if (*extra == '\0') extra = argv[++i];
      lua_assert(extra != NULL);
      status = (option == 'e')
               ? dostring(L, extra, "=(command line)")
               : dolibrary(L, extra);
      if (status != LUA_OK) return 0;
    }
  }
  return 1;
}



static int handle_luainit (lua_State *L) {
  const char *name = "=" LUA_INITVARVERSION;
  const char *init = getenv(name + 1);
  if (init == NULL) {
    name = "=" LUA_INIT_VAR;
    init = getenv(name + 1);  /* try alternative name */
  }
  if (init == NULL) return LUA_OK;
  else if (init[0] == '@')
    return dofile(L, init+1);
  else
    return dostring(L, init, name);
}


/*
** Main body of stand-alone interpreter (to be called in protected mode).
** Reads the options and handles them all.
*/
static int pmain (lua_State *L) {
	/*
  int argc = (int)lua_tointeger(L, 1);
  char **argv = (char **)lua_touserdata(L, 2);
  int script;
  int args = collectargs(argv, &script);
	*/
  luaL_checkversion(L);    /* check that interpreter has correct version */

	print_version();
      doREPL(L);  /* do read-eval-print loop */
  lua_pushboolean(L, 1);  /* signal no errors */
  return 1;
}

// FILE *stream_out=NULL;
// FILE *stream_err=NULL;
// FILE *stream_in=NULL;
static  void DispConsole()
{
    // ¥³¥ó¥½©`¥�Eò×÷³É¤¹¤�E
    AllocConsole();
    // ˜ËœÊÈ�EöÁ¦¤Ë¸ûÀ�E±¤Æ¤�E
    // FILE* fp = NULL;
    // Îô¤Î¥³©`¥É
    //freopen("CONOUT$", "w", stdout);
    //freopen("CONIN$", "r", stdin);
    // ¬FÔÚ¤Î¥³©`¥É
    // freopen_s(&fp, "CONOUT$", "w", stdout);
    // freopen_s(&fp, "CONOUT$", "w", stderr); 
    // freopen_s(&fp, "CONIN$", "r", stdin);
	
    freopen( "CONOUT$", "w", stdout);
    freopen( "CONOUT$", "w", stderr); 
    freopen( "CONIN$", "r", stdin);
	
    // freopen_s(&stream_out, "CONOUT$", "w", stdout);
    // freopen_s(&stream_err, "CONOUT$", "w", stderr); 
    // freopen_s(&stream_in, "CONIN$", "r", stdin);

}
static int luaB_print (lua_State *L) {
  int n = lua_gettop(L);  /* number of arguments */
  int i;
  lua_getglobal(L, "tostring");
  for (i=1; i<=n; i++) {
    const char *s;
    size_t l;
    lua_pushvalue(L, -1);  /* function to be called */
    lua_pushvalue(L, i);   /* value to print */
    lua_call(L, 1, 1);
    s = lua_tolstring(L, -1, &l);  /* get result */
    if (s == NULL)
      return luaL_error(L, "'tostring' must return a string to 'print'");
    if (i>1) lua_writestring("\t", 1);
    lua_writestring(s, l);
    lua_pop(L, 1);  /* pop result */
  }
  lua_writeline();
  return 0;
}
static int luaB_error (lua_State *L) {
  int level = (int)luaL_optinteger(L, 2, 1);
  lua_settop(L, 1);
  if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
    luaL_where(L, level);   /* add extra information */
    lua_pushvalue(L, 1);
    lua_concat(L, 2);
  }
  return lua_error(L);
}

static int lua_cmd (lua_State *L) {
  int status, result;
	DispConsole();
 lua_register(L, "print", luaB_print);
 lua_register(L, "error", luaB_error);
  lua_pushcfunction(L, &pmain);  /* to call 'pmain' in protected mode */
  status = lua_pcall(L, 0, 1, 0);  /* do the call */
  result = lua_toboolean(L, -1);  /* get result */
  report(L, status);
  //  lua_close(L);
	FreeConsole();
  return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
}

static char buffer[16384]; // buffer for reading from a process
static char linebuf[512];  // line buffer
static char outbuf[16384]; // buffer for constructing messages to SciTE
static int fulllines = 1;
HWND hGwnd=NULL;
static HWND hSciTE;
static HWND hSelf;
static HINSTANCE hInstance;
HINSTANCE hInstanceDll;

// Director interface to other SciTE instances.
static int SendToHandle(HWND hwnd, const char *Message)
{
	COPYDATASTRUCT cds;
	int size = strlen(Message);
	cds.dwData = 0;
	cds.lpData = (void *)Message;
	cds.cbData = size;
	return SendMessage(hwnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
}

static int size_of_array(HWND* results)
{
	int idx = 0;
	// find our place in the output array	
	for (idx = 0; results[idx] != NULL; idx++);
	return idx;
}

BOOL CALLBACK EnumWindowsProc(HWND  hwnd, LPARAM  lParam)
{
	HWND* results = (HWND*)lParam;
	int idx = size_of_array(results);
	char buff[256];
	GetClassNameA(hwnd, buff, sizeof(buff));
	if (strcmp(buff, "DirectorExtension") == 0){
		if (GetWindowLongPtr(hwnd, GWLP_USERDATA) == (LONG_PTR)hSciTE){
			hSelf = hwnd;
		} else {
			results[idx] = hwnd;
			results[idx+1] = NULL;
		} 
	}
	return TRUE;
}

// 0 refers to current instance, 1,2...etc to other instances.
static int do_perform(lua_State* L)
{
	char buff[128];
	const char* cmd = lua_tostring(L, 1);
	int this_instance = lua_tointeger(L, 2);
	HWND results[50];
	int nmsg;
	results[0] = 0;
	EnumWindows(EnumWindowsProc, (LPARAM)results);
	nmsg = size_of_array(results);
	if (this_instance > nmsg){
		lua_pushnil(L);
		lua_pushliteral(L, "no other instance available");
		return 2;
	} else {
		int res = SendToHandle(this_instance ? results[this_instance-1] : hSelf, cmd);
		lua_pushinteger(L, res);
		return 1;
	}
}

static int do_foreground(lua_State* L)
{
	SetForegroundWindow(hSciTE);
	return 0;
}

static int do_verbose(lua_State* L)
{
	return 0;
}

static int do_fulllines(lua_State* L)
{
	//fulllines = luaL_checkboolean(L,1);
	return 0;
}

const UINT STE_WM_ONEXECUTE = 2001;

static void exec_lua(lua_State* L, const char* fun, const char* args)
{
	lua_getglobal(L, fun);
	lua_pushstring(L, args);
	if (lua_pcall(L, 1, 0, 0)!= 0){
		lua_getglobal(L, "print");
		lua_pcall(L, 1, 0, 0);
	}
}


LRESULT PASCAL WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	WNDPROC lpPrevWndProc;
	if (uMsg == STE_WM_ONEXECUTE){
		lua_State *L = (lua_State *)wParam;
		char* args = (char *)lParam;
		char* fun, *arg;
		char* ptr = strchr(args, ' ');
		*ptr = '\0';
		fun = args;
		arg = ptr+1;
		exec_lua(L, fun, arg);
		free(args);
		return 0;
	}
	
	lpPrevWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
	if (lpPrevWndProc)
		return CallWindowProc(lpPrevWndProc, hwnd, uMsg, wParam, lParam);
	
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

static HWND hwndDispatcher;

void create_thread_window(void)
{
	LONG_PTR subclassedProc;
	hwndDispatcher = CreateWindowA(
		"STATIC", "SciTE_Spawner_Dispatcher",
		0, 0, 0, 0, 0, 0, 0, GetModuleHandleA(NULL), 0
	);
	subclassedProc = SetWindowLongPtr(hwndDispatcher, GWLP_WNDPROC, (LONG_PTR)WndProc);
	SetWindowLongPtr(hwndDispatcher, GWLP_USERDATA, subclassedProc);
}

#define SPAWNER "SPAWNER"

typedef struct {
	const char* command_line;
	const char* output;
	const char* result;
	lua_State* L;
	BOOL peeking;
	BOOL running;
	HANDLE hProcess;
	PROCESS_INFORMATION pi;
	HANDLE hWriteSubProcess;
	HANDLE hPipeRead;
	HANDLE hPipeWrite;
	FILE* inf;
} Spawner;


static BOOL start_process(Spawner* p)
{
	const char* prog = p->command_line;
	SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), 0, 0};
	SECURITY_DESCRIPTOR sd;
	STARTUPINFOA si = {
		sizeof(STARTUPINFO), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	};
	
	HANDLE hRead2;
	HANDLE hProcess = GetCurrentProcess();
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;
	InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
	SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = &sd;
	
	// Create pipe for output redirection
	// read handle, write handle, security attributes,  number of bytes reserved for pipe - 0 default
	CreatePipe(&p->hPipeRead, &p->hPipeWrite, &sa, 0);
	
	// Create pipe for input redirection. In this code, you do not
	// redirect the output of the child process, but you need a handle
	// to set the hStdInput field in the STARTUP_INFO struct. For safety,
	// you should not set the handles to an invalid handle.
	
	hRead2 = NULL;
	// read handle, write handle, security attributes,  number of bytes reserved for pipe - 0 default
	CreatePipe(&hRead2, &p->hWriteSubProcess, &sa, 0);
	
	SetHandleInformation(p->hPipeRead, HANDLE_FLAG_INHERIT, 0);
	SetHandleInformation(p->hWriteSubProcess, HANDLE_FLAG_INHERIT, 0);
	
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdInput = hRead2;
	si.hStdOutput = p->hPipeWrite;
	si.hStdError = p->hPipeWrite;
	
	p->running = CreateProcessA(
		NULL,
		(char*)prog,
		NULL, NULL,
		TRUE, CREATE_NEW_PROCESS_GROUP,
		NULL,
		NULL, // start directory
		&si, &p->pi);
	
	CloseHandle(p->pi.hThread);
	CloseHandle(hRead2);
	CloseHandle(p->hPipeWrite);
	return p->running;
}

static void send_to_scite(lua_State* L, const char* fun, const char* args)
{
	char* command = (char*)malloc(strlen(fun)+strlen(args)+1+1);
	sprintf(command, "%s %s", fun, args);
	SendMessage(hwndDispatcher, STE_WM_ONEXECUTE, (WPARAM)L, (LPARAM)command);
}

static void monitor_process(Spawner* p)
{
	DWORD exitcode;
	if (WAIT_OBJECT_0 == WaitForSingleObject(p->pi.hProcess, INFINITE)){
		GetExitCodeProcess(p->pi.hProcess, &exitcode);
		CloseHandle(p->pi.hProcess);
		if (p->result){
			sprintf(buffer, "%d", exitcode);
			send_to_scite(p->L, p->result, buffer);
		}	
	}
}


static void run_process(void * arg)
{
	DWORD bytesRead = 0;
	DWORD bytesBuffer,byteLine;
	BOOL bTest;
	DWORD exitcode;
	char  *pLf,*pLf2,*base;
	Spawner* p = (Spawner*)arg;
	//* FILE* reader = fdopen(p->hPipeRead,"r");
	Sleep(50);
	while (p->running){
		memset(buffer, 0x00, sizeof(buffer));
		bytesBuffer=0;
		while (1){
			if ((bytesBuffer+sizeof(linebuf))> sizeof(buffer))
				break;
			bTest = ReadFile(p->hPipeRead, linebuf,
				sizeof(linebuf)-1, &bytesRead, NULL);
			if (bTest && bytesRead){
				linebuf[bytesRead] = '\0';
                base=linebuf;
				pLf=strchr(base,'\n');
				if(fulllines && pLf){
					pLf++;
                    byteLine=pLf-base;
                    while ( byteLine< bytesRead ){
                        strncpy(buffer+bytesBuffer, base,byteLine);
                        //buffer[bytesBuffer+byteLine]='\0';
                        // send_to_scite(p->L, p->output, buffer);
                       // *buffer = '\0';
                       // bytesBuffer=0;
						bytesBuffer += byteLine;
                        bytesRead-=byteLine;
                        base+=byteLine;
                        pLf=strchr(base,'\n');
                        if(!pLf)
                            break;
                        pLf++;
                        byteLine=pLf-base;
                    }
					if (byteLine < bytesRead){
						buffer[bytesBuffer] = '\0';
						send_to_scite(p->L, p->output, buffer);
						memset(buffer, 0x00, sizeof(buffer));
						bytesBuffer = 0;
					}
				}

				strncpy(buffer+bytesBuffer, base,bytesRead);
				bytesBuffer=bytesBuffer+bytesRead;
				buffer[bytesBuffer] = '\0';
				if (fulllines && base[bytesRead-1] == '\n'){
					break;
				}
			} else {
				p->running = FALSE;
				break;
			}
		}
		send_to_scite(p->L, p->output, buffer);
	}
	GetExitCodeProcess(p->pi.hProcess, &exitcode);
	CloseHandle(p->pi.hProcess);
	if (p->result){
		sprintf(buffer, "%d", exitcode);
		send_to_scite(p->L, p->result, buffer);
	}
	//* fclose(reader);
	CloseHandle(p->hPipeRead);
}


static int new_spawner(lua_State* L)
{
	Spawner* spp = (Spawner*)lua_newuserdata(L, sizeof(Spawner));
	memset(spp, 0, sizeof(Spawner));
	spp->command_line = luaL_checkstring(L, 1);
	spp->L = L;
	luaL_getmetatable(L, SPAWNER);
	lua_setmetatable(L, -2);
	return 1;
}

static int spawner_set_output(lua_State* L)
{
	Spawner* spp = (Spawner*)lua_touserdata(L, 1);
	spp->output = luaL_checkstring(L, 2);
	return 0;
}

static int spawner_set_result(lua_State* L)
{
	Spawner* spp = (Spawner*)lua_touserdata(L, 1);
	spp->result = luaL_checkstring(L, 2);
	return 0;
}

static int spawner_use_shell(lua_State* L)
{
	Spawner* spp = (Spawner*)lua_touserdata(L, 1);
	char* new_command;
	const char* comspec = getenv("COMSPEC");
	if (! comspec)comspec = "CMD.EXE";
	new_command = (char*)malloc(strlen(spp->command_line)+20);
	sprintf(new_command, "%s /c %s", comspec, spp->command_line);
	spp->command_line = new_command;
	return 0;
}

static int spawner_write(lua_State* L)
{
	Spawner* spp = (Spawner*)lua_touserdata(L, 1);
	const char* buff = luaL_checkstring(L, 2);
	DWORD bytesWrote;
	DWORD nReaded = strlen(buff);
	WriteFile(spp->hWriteSubProcess, buff, nReaded, &bytesWrote, NULL);
	lua_pushboolean(L, nReaded == bytesWrote);
	return 1;
}

static int spawner_read(lua_State* L)
{
	Spawner* spp = (Spawner*)lua_touserdata(L, 1);
	char* res = fgets(buffer, sizeof(buffer), spp->inf);
	if (res){
		lua_pushstring(L, buffer);
		return 1;
	} else {
		lua_pushnil(L);
	}
	return 1;
}

static void newfile_from_handle(lua_State *L, HANDLE handle, const char* mode);

static int spawner_run(lua_State* L)
{
	Spawner* spp = (Spawner*)lua_touserdata(L, 1);
	if (! start_process(spp)){
		lua_pushboolean(L, FALSE);
		return 1;
	}
	//_beginthread(monitor_process,0,spp);
	if (spp->output != NULL){
		_beginthread(run_process, 1024 * 1024, spp);
	} else {
		int fd;
		fd = _open_osfhandle((intptr_t)spp->hPipeRead, _O_BINARY);
		spp->inf = _fdopen(fd, "r");
		//Sleep(50);
	}
	lua_pushboolean(L, TRUE);
	return 1;
}

static Spawner* start_popen(lua_State* L)
{
	Spawner* spp = (Spawner*)malloc(sizeof(Spawner));
	const char* comspec = getenv("COMSPEC");
	char* new_command;
	size_t len;
	char *cmd;
	
	memset(spp, 0, sizeof(Spawner));
	spp->command_line = luaL_checkstring(L, 1);
	
	len = AnsicFromutf8(spp->command_line, -1, NULL);
	cmd = (char *)malloc(len);
	len = AnsicFromutf8(spp->command_line, -1, cmd);
	
	if (! comspec)comspec = "CMD.EXE";
	new_command = (char*)malloc(strlen(cmd)+ strlen(comspec)+ 20);
	sprintf(new_command, "%s /c %s", comspec, cmd);
	free(cmd);
	spp->command_line = new_command;
	if (! start_process(spp)){
		lua_pushboolean(L, FALSE);
		return NULL;
	}
	//_beginthread(monitor_process,0,spp);
	return spp;
}

static int do_popen(lua_State* L)
{
	Spawner* spp = start_popen(L);
	newfile_from_handle(L, spp->hPipeRead, "rt");
	return 1;
}

static int do_popen2(lua_State* L)
{
	Spawner* spp = start_popen(L);
	newfile_from_handle(L, spp->hWriteSubProcess, "wt");
	newfile_from_handle(L, spp->hPipeRead, "rt");
	return 2;
}

static int do_ans_to_utf8(lua_State* L)
{
	size_t len;
	char *utf8Code;
	const char*  ansCode = luaL_checkstring(L, 1);
	len = Utf8FromAnsic(ansCode, -1, NULL);
	utf8Code = (char *)malloc(len);
	len = Utf8FromAnsic(ansCode, -1, utf8Code);
	lua_pushstring(L, utf8Code);
	free(utf8Code);
	return 1;
}
static int do_utf8_to_ans(lua_State* L)
{
	size_t len;
	char *ansCode;
	const char*  utf8Code = luaL_checkstring(L, 1);
	len = AnsicFromutf8(utf8Code, -1, NULL);
	ansCode = (char *)malloc(len);
	len = AnsicFromutf8(utf8Code, -1, ansCode);
	lua_pushstring(L, ansCode);
	free(ansCode);
	return 1;
}
static int send_wm_copydata(lua_State* L)
{
	int result;
	
	// get the parameters
	HWND hwnd = (HWND)luaL_checkinteger(L, 1);
	const char*  msg = luaL_checkstring(L, 2);
	result = SendToHandle(hwnd, msg);
	
	// return the number that the window gave to us
	lua_pushinteger(L, result);
	return 1;
}
// SendMessage(hwnd,msg, wParam, lParam) -- Sends a message to the a window.
static int do_SendMessage(lua_State* L)
{
	int result;
	
	// get the parameters
	HWND hwnd = (HWND)luaL_checkinteger(L, 1);
	int iMsg = luaL_checkinteger(L, 2);
	int wParam = luaL_checkinteger(L, 3);
	int lParam = luaL_checkinteger(L, 4);
	
	if (IsWindow(hwnd))// invalid window?
	{
		// just dispatch the message to the window
		result = (int)SendMessageA(hwnd, (UINT)iMsg, (WPARAM)wParam, (LPARAM)lParam);
	}else{
		//return luaL_error(L, "Invalid window handle.");
		result = -1;
	}
	// return the number that the window gave to us
	lua_pushinteger(L, result);
	return 1;
}
// PostMessage(hwnd,msg, wParam, lParam) -- Posts a message to the a window.
static int do_PostMessage(lua_State* L)
{
	int result;
	
	// get the parameters
	HWND hwnd = (HWND)luaL_checkinteger(L, 1);
	int iMsg = luaL_checkinteger(L, 2);
	int wParam = luaL_checkinteger(L, 3);
	int lParam = luaL_checkinteger(L, 4);
	
	if (IsWindow(hwnd))// invalid window?
	{
		// just dispatch the message to the window
		result = PostMessageA(hwnd, (UINT)iMsg, (WPARAM)wParam, (LPARAM)lParam);
	}else{
		//return luaL_error(L, "Invalid window handle.");
		result = -1;
	}
	
	// return the return code
	lua_pushboolean(L, result);
	return 1;
}
// pumpmsg(msg, wparam, lparam) -- Sends a message in which lParam will be received as a string.
static int do_SendMsgStr(lua_State* L)
{
	DWORD pID;
	HANDLE hProcess;
	void* rlParam;
	int result;

	// get the parameters
	// get the parameters
	HWND hwnd = (HWND)luaL_checkinteger(L, 1);
	int iMsg = luaL_checkinteger(L, 2);
	int wParam = luaL_checkinteger(L, 3);
	const char* lParam = luaL_checkstring(L, 4);

	// get the string length
	size_t lParamSize = strlen(lParam) + 1;

	if (!IsWindow(hwnd)) // invalid window?
		return luaL_error(L, "Invalid window handle.");

	// inject the string at the process.
	GetWindowThreadProcessId(hwnd, &pID);
	hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, 0, pID);
	if (!hProcess)
		return luaL_error(L, "Couldn't open the memory of the window!");
	rlParam = VirtualAllocEx(hProcess, 0, lParamSize, MEM_COMMIT, PAGE_READWRITE);
	if (!rlParam)
		return luaL_error(L, "Couldn't allocate the memory at the window!");
	if (!WriteProcessMemory(hProcess, rlParam, lParam, lParamSize, NULL))
		return luaL_error(L, "Couldn't inject the string parameter at the window!");

	// just dispatch the message to the window
	result = (int) SendMessageA(hwnd, (UINT)iMsg, (WPARAM)wParam, (LPARAM)rlParam);

	// free the memory used by the string
	if (!VirtualFreeEx(hProcess, rlParam, 0, MEM_RELEASE))
		return luaL_error(L, "Failed to free the memory at the window!");
	if (!CloseHandle(hProcess))
		return luaL_error(L, "Couldn't close the process handle!");

	// return the number that the window gave to us
	lua_pushinteger(L, result);
	return 1;
}
// GetMessage( msg ) -- GetMessage from addr.
static int do_GetMessage(lua_State* L)
{
	const char* sMessage = ( const char* )luaL_checkinteger(L, 1);
	lua_pushstring(L, sMessage);
	return 1;
}
static int spawner_kill(lua_State* L)
{
	Spawner* spp = (Spawner*)lua_touserdata(L, 1);
	TerminateProcess(spp->pi.hProcess, 2);
	spp->pi.hProcess = NULL;
	return 0;
}


/////// stuff from liolib

#define PIPE_FILEHANDLE "PIPE_FILE*"

// based on liolib.c
static void newfile_from_handle(lua_State *L, HANDLE handle, const char* mode)
{
	FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
	int fd;
	*pf = NULL;
	luaL_getmetatable(L, PIPE_FILEHANDLE);
	lua_setmetatable(L, -2);
	fd = _open_osfhandle((intptr_t)handle, _O_TEXT);
	*pf = _fdopen(fd, mode);
	// leaves the userdata on the lua stack!
}

static int pushresult(lua_State *L, int i, const char *filename){
	int en = errno; /* calls to Lua API may change this value */
	if (i){
		lua_pushboolean(L, 1);
		return 1;
	}
	else {
		lua_pushnil(L);
		if (filename)
			lua_pushfstring(L, "%s: %s", filename, strerror(en));
		else
			lua_pushfstring(L, "%s", strerror(en));
		lua_pushinteger(L, en);
		return 3;
	}
}

static FILE *tofile(lua_State *L){
	FILE **f = (FILE **)luaL_checkudata(L, 1, PIPE_FILEHANDLE);
	if (*f == NULL)
		luaL_error(L, "attempt to use a closed file");
	return *f;
}

static int f_close(lua_State *L){
	FILE *f = tofile(L);
	fclose(f);
	return 0;
}

static int read_line(lua_State *L, FILE *f);

static int io_readline(lua_State *L){
	FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
	int sucess;
	if (f == NULL)/* file is already closed? */
		luaL_error(L, "file is already closed");
	sucess = read_line(L, f);
	if (ferror(f))
		return luaL_error(L, "%s", strerror(errno));
	if (sucess)return 1;
	else {  /* EOF */
		return 0;
	}
}

static int f_lines(lua_State *L){
	tofile(L); /* check that it's a valid file handle */
	lua_pushvalue(L, 1);
	lua_pushcclosure(L, io_readline, 1);
	return 1;
}

static int read_number(lua_State *L, FILE *f){
	lua_Number d;
	if (fscanf(f, "%lf", &d) == 1){
		lua_pushnumber(L, d);
		return 1;
	}
	else return 0; /* read fails */
}


static int test_eof(lua_State *L, FILE *f){
	int c = getc(f);
	ungetc(c, f);
	lua_pushlstring(L, NULL, 0);
	return(c != EOF);
}


static int read_line(lua_State *L, FILE *f){
	luaL_Buffer b;
	luaL_buffinit(L, &b);
	for (;; ){
		size_t l;
		char *p = luaL_prepbuffer(&b);
		if (fgets(p, LUAL_BUFFERSIZE, f) == NULL){  /* eof? */
			luaL_pushresult(&b); /* close buffer */
			return(lua_rawlen(L, -1)> 0); /* check whether read something */
		}
		l = strlen(p);
		if (l == 0 || p[l-1] != '\n')
			luaL_addsize(&b, l);
		else {
			luaL_addsize(&b, l - 1); /* do not include `eol' */
			luaL_pushresult(&b); /* close buffer */
			return 1; /* read at least an `eol' */
		}
	}
}


static int read_chars(lua_State *L, FILE *f, size_t n){
	size_t rlen; /* how much to read */
	size_t nr; /* number of chars actually read */
	luaL_Buffer b;
	luaL_buffinit(L, &b);
	rlen = LUAL_BUFFERSIZE; /* try to read that much each time */
	do {
		char *p = luaL_prepbuffer(&b);
		if (rlen > n)rlen = n; /* cannot read more than asked */
		nr = fread(p, sizeof(char), rlen, f);
		luaL_addsize(&b, nr);
		n -= nr; /* still have to read `n' chars */
	} while (n > 0 && nr == rlen); /* until end of count or eof */
	luaL_pushresult(&b); /* close buffer */
	return(n == 0 || lua_rawlen(L, -1)> 0);
}


static int f_read(lua_State *L){
	FILE *f = tofile(L);
	int nargs = lua_gettop(L)- 1;
	int success;
	int n;
	clearerr(f);
	if (nargs == 0){  /* no arguments? */
		success = read_line(L, f);
		n = 2+1; /* to return 1 result */
	}
	else {  /* ensure stack space for all results and for auxlib's buffer */
		luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
		success = 1;
		for (n = 2; nargs-- && success; n++){
			if (lua_type(L, n) == LUA_TNUMBER){
				size_t l = (size_t)lua_tointeger(L, n);
				success = (l == 0)? test_eof(L, f): read_chars(L, f, l);
			}
			else {
				const char *p = lua_tostring(L, n);
				luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
				switch(p[1]){
					case 'n':  /* number */
						success = read_number(L, f);
						break;
					case 'l':  /* line */
						success = read_line(L, f);
						break;
					case 'a':  /* file */
						read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
						success = 1; /* always success */
						break;
					default:
						return luaL_argerror(L, n, "invalid format");
				}
			}
		}
	}
	if (ferror(f))
		return pushresult(L, 0, NULL);
	if (!success){
		lua_pop(L, 1); /* remove last result */
		lua_pushnil(L); /* push nil instead */
	}
	return n - 2;
}


static int f_write(lua_State *L)
{
	FILE *f = tofile(L);
	int nargs = lua_gettop(L)- 1;
	int status = 1;
	int arg = 2;
	for (; nargs--; arg++){
		if (lua_type(L, 2) == LUA_TNUMBER){
			/* optimization: could be done exactly as for strings */
			status = status &&
			fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg))> 0;
		}
		else {
			size_t l;
			const char *s = luaL_checklstring(L, arg, &l);
			status = status && (fwrite(s, sizeof(char), l, f) == l);
		}
	}
	return pushresult(L, status, NULL);
}


static int f_flush(lua_State *L){
	return pushresult(L, fflush(tofile(L)) == 0, NULL);
}

static const luaL_Reg spawner[] = {
	{"foreground", do_foreground},
	{"verbose", do_verbose},
	{"fulllines", do_fulllines},
	{"new", new_spawner},
	{"popen", do_popen},
	{"popen2", do_popen2},
	{"perform", do_perform},
	{"lua_cmd", lua_cmd},
	{"ans_to_utf8", do_ans_to_utf8},
	{"utf8_to_ans", do_utf8_to_ans},
	{"sendMessage", do_SendMessage},
	{"postMessage", do_PostMessage},
	{"sendMsgStr", do_SendMsgStr},
	{"getMessage", do_GetMessage},
	{"sendWmCopydata", send_wm_copydata},
	{NULL, NULL}
};

static const luaL_Reg spawner_methods[] = {
	{"set_output", spawner_set_output},
	{"set_result", spawner_set_result},
	{"use_shell", spawner_use_shell},
	{"write", spawner_write},
	{"read", spawner_read},
	{"kill", spawner_kill},
	{"run", spawner_run},
	{NULL, NULL}
};


static const luaL_Reg file_methods[] = {
	{"close", f_close},
	{"flush", f_flush},
	{"lines", f_lines},
	{"read", f_read},
	{"write", f_write},
	{NULL, NULL}
};

static void createmeta(lua_State *L){
	luaL_newmetatable(L, PIPE_FILEHANDLE); /* create metatable for file handles */
	lua_pushvalue(L, -1); /* push metatable */
	lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
	//luaL_register(L, NULL, file_methods); /* file methods */
	luaL_setfuncs(L, file_methods, 0);
}

static int luaB_32or64 (lua_State *L) {
    int bits= sizeof(char *);
    int arch=8*bits;;
    //‘ø¤ê‚Ž¤ò¥¹¥¿¥Ã¥¯¤Ë·e¤à
    lua_pushinteger(L, arch);
    return 1;
}

static int log_init(HINSTANCE hinstDLL, DWORD fdwReason){
	ComLogger::init();
	ComLogger::open("win32-spawner-ex");
	COMLOGF(RT_D_DEBUG, "hinstDLL(0x%X)fdwReason(%d) ",hinstDLL,fdwReason);
	return 1;
}

#ifdef _M_AMD64
#define GWL_HINSTANCE	GWLP_HINSTANCE
#endif
#ifdef __cplusplus
extern "C" {

__declspec(dllexport)
int luaopen_spawner(lua_State *L)
{
// static int init=log_init();
	luaDll_get_State(L);
	COMLOGF(RT_I_INFO, "L=(%d|0x%p)",L, L);
	int   nFlg=0;
	lua_getglobal(L,"props");
	if (lua_isnil(L, -1)) {
		nFlg=1;
	}
	lua_getfield(L, -1, "MainHwnd");
	if (lua_isnil(L, -1)) {
		nFlg=1;
	}
	if( nFlg==1 ){
		hSciTE = GetForegroundWindow();
	}
	else{
		int type = lua_type(L, -1);
		const char *p = lua_tostring(L, -1);
		COMLOGF(RT_I_INFO, "type=(%d);p=[%s]",type,p);
		#ifdef _WIN64
		hSciTE =reinterpret_cast <HWND> (strtoll(p,NULL, 0));
		#else
		hSciTE =reinterpret_cast <HWND> (strtol(p,NULL, 0));
		#endif
	}
	lua_settop(L, 0);
	COMLOGF(RT_I_INFO, "nFlg=(%d);hSciTE=(%d|0x%p)",nFlg,hSciTE, hSciTE);
    hGwnd=hSciTE;
	hInstance = (HINSTANCE)GetWindowLongPtr(hSciTE, GWL_HINSTANCE);
	create_thread_window();
	createmeta(L);

	lua_register(L, "x32or64", luaB_32or64);
	cf_hWnds_vec_init(L);
	lua_setEquipment(L);

	lua_getglobal(L, "spawner");
	if (lua_isnil(L, -1)) {
	  lua_pop(L, 1);
	  lua_newtable(L);
	}
	luaL_setfuncs(L, spawner, 0);
	lua_setglobal(L, "spawner");

	//luaL_register(L, "spawner", spawner);
	luaL_newmetatable(L, SPAWNER); // create metatable for spawner objects
	lua_pushvalue(L, -1); // push metatable
	lua_setfield(L, -2, "__index"); // metatable.__index = metatable
	//luaL_register(L, NULL, spawner_methods);
	luaL_setfuncs(L, spawner_methods, 0);
	return 1;
}

extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	
  switch (fdwReason)
  {
    case DLL_PROCESS_ATTACH:
	static int init=log_init(hinstDLL,fdwReason);
	COMLOGF(RT_D_DEBUG, "hinstDLL(0x%X)DLL_PROCESS_ATTACH(%d) ",hinstDLL,fdwReason);
      /* Code path executed when DLL is loaded into a process's address space. */
      hInstanceDll=hinstDLL;
      break;

    case DLL_THREAD_ATTACH:
	COMLOGF(RT_D_DEBUG, "hinstDLL(0x%X)DLL_THREAD_ATTACH(%d) ",hinstDLL,fdwReason);
      /* Code path executed when a new thread is created within the process. */
      hInstanceDll=hinstDLL;
      break;

    case DLL_THREAD_DETACH:
	COMLOGF(RT_D_DEBUG, "hinstDLL(0x%X)DLL_THREAD_DETACH(%d) ",hinstDLL,fdwReason);
      /* Code path executed when a thread within the process has exited *cleanly*. */
      // hInstanceDll=NULL;
      break;

    case DLL_PROCESS_DETACH:
	COMLOGF(RT_D_DEBUG, "hinstDLL(0x%X)DLL_PROCESS_DETACH(%d) ",hinstDLL,fdwReason);
      /* Code path executed when DLL is unloaded from a process's address space. */
      COMLOGF(RT_D_DEBUG, "init(%d) ",init);
	ComLogger::close();
      hInstanceDll=NULL;
      break;
  }

  return TRUE;
}

}
#endif



