#include "stdafx.h" #define MT_ENVIRONMENT "ENVIRONMENT" extern PLUGININFOEX pluginInfoEx; EXTERN_C MIR_APP_DLL(void) RegisterPlugin(CMPluginBase *pPlugin); EXTERN_C MIR_APP_DLL(void) UnregisterPlugin(CMPluginBase *pPlugin); CMLuaEnvironment::CMLuaEnvironment(lua_State *L) : CMPluginBase(nullptr, pluginInfoEx), L(L) { m_hInst = (HINSTANCE)this; ::RegisterPlugin(this); } int CMLuaEnvironment::Unload() { ::UnregisterPlugin(this); KillObjectEventHooks(this); KillObjectServices(this); for (auto &it : m_hookRefs) luaL_unref(L, LUA_REGISTRYINDEX, it.second); for (auto &it : m_serviceRefs) luaL_unref(L, LUA_REGISTRYINDEX, it.second); return 0; } CMLuaEnvironment* CMLuaEnvironment::GetEnvironment(lua_State *L) { if (!luaM_getenv(L)) return nullptr; lua_rawgeti(L, -1, NULL); CMLuaEnvironment *env = (CMLuaEnvironment*)lua_touserdata(L, -1); lua_pop(L, 3); return env; } HPLUGIN CMLuaEnvironment::GetEnvironmentId(lua_State *L) { CMLuaEnvironment *env = GetEnvironment(L); return env != nullptr ? HPLUGIN(env) : &g_plugin; } static int HookEventEnvParam(void *obj, WPARAM wParam, LPARAM lParam, LPARAM param) { CMLuaEnvironment *env = (CMLuaEnvironment*)obj; int ref = param; lua_rawgeti(env->L, LUA_REGISTRYINDEX, ref); if (wParam) lua_pushlightuserdata(env->L, (void*)wParam); else lua_pushnil(env->L); if (lParam) lua_pushlightuserdata(env->L, (void *)lParam); else lua_pushnil(env->L); luaM_pcall(env->L, 2, 1); return lua_tointeger(env->L, -1); } HANDLE CMLuaEnvironment::HookEvent(const char *name, int ref) { HANDLE hHook = HookEventObjParam(name, HookEventEnvParam, this, ref); if (hHook) m_hookRefs[hHook] = ref; return hHook; } int CMLuaEnvironment::UnhookEvent(HANDLE hEvent) { int res = ::UnhookEvent(hEvent); if (res) { auto it = m_hookRefs.find(hEvent); if (it != m_hookRefs.end()) luaL_unref(L, LUA_REGISTRYINDEX, it->second); } return res; } static INT_PTR CreateServiceFunctionEnvParam(void *obj, WPARAM wParam, LPARAM lParam, LPARAM param) { CMLuaEnvironment *env = (CMLuaEnvironment*)obj; int ref = param; lua_rawgeti(env->L, LUA_REGISTRYINDEX, ref); lua_pushlightuserdata(env->L, (void *)wParam); lua_pushlightuserdata(env->L, (void *)lParam); luaM_pcall(env->L, 2, 1); INT_PTR res = lua_tointeger(env->L, 1); lua_pushinteger(env->L, res); return res; } HANDLE CMLuaEnvironment::CreateServiceFunction(const char *name, int ref) { HANDLE hService = CreateServiceFunctionObjParam(name, CreateServiceFunctionEnvParam, this, ref); if (hService) m_serviceRefs[hService] = ref; return hService; } void CMLuaEnvironment::DestroyServiceFunction(HANDLE hService) { auto it = m_serviceRefs.find(hService); if (it != m_serviceRefs.end()) luaL_unref(L, LUA_REGISTRYINDEX, it->second); ::DestroyServiceFunction(hService); } void CMLuaEnvironment::CreateEnvironmentTable() { if (!lua_isfunction(L, -1)) return; lua_createtable(L, 1, 1); lua_pushlightuserdata(L, this); lua_rawseti(L, -2, NULL); lua_pushvalue(L, -1); lua_setfield(L, -2, "_G"); lua_createtable(L, 0, 2); lua_pushliteral(L, MT_ENVIRONMENT); lua_setfield(L, -2, "__metatable"); lua_getglobal(L, "_G"); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); lua_setupvalue(L, -2, 1); } /***********************************************/ wchar_t* CMLuaEnvironment::Error() { const char *message = lua_tostring(L, -1); wchar_t *error = mir_utf8decodeW(message); lua_pop(L, 1); return error; } int CMLuaEnvironment::Call() { CreateEnvironmentTable(); return lua_pcall(L, 0, 1, 0); } int CMLuaEnvironment::Eval(const wchar_t *script) { if (int res = luaL_loadstring(L, T2Utf(script))) return res; return Call(); } int CMLuaEnvironment::Exec(const wchar_t *path) { if (int res = luaL_loadfile(L, T2Utf(path))) return res; return Call(); }