IR SDK FireEvent enhanced

Esta sección esta especialmente diseñada para todos aquellos usuarios que estés desarrollando plugins o aplicaciones y quieran ayuda para dichos plugins o aplicaciones.
The IR SDK contains a key method derivated of CIRPluginObject "FireEvent" which is being used as its name suggest, firing object events. This api is quite rudimentary as its using a string to populate the arguments for calling the event, this result on a wide range of problems that discourages developers to use events, for example:
  • Lengths are short, those buffers are limited to some 2000 bytes, some event could need more buffer
  • You have to format lua compilant syntax and well escaped strings, if you know how hard could this be
  • Execution context of this api is not thread safe, thus while it would be possible to develop threaded objects, this api should not be used, this is why most of crashes are produced on my old MultiThread Object, which relied on FireEvent
  • While lua could work with unicode strings, this api renders impossible to do it on events
  • They dont return. You cannot control the code flow by vars changed on the event, but have to call api. Sometimes this is quite hard or impossible or introduce a performance downgrade
To overcome this issue best would be to have the source code of event action, thats something possible with existent api. FireEvent accepts 3 arguments, the object ptr, the event and the code to execute, the object ptr is accesible with the undocumented method Page.GetPluginObjectPtr that convers a plugin name into a ptr. To get the code, we should call Page.GetObjectScript that uses the object name and event name. As plugin instance internally dont know the name it has assigned, we need some code to obtain the name.

In this case ive used lua2c with this stub
local _v_objects = Page.EnumerateObjects();
for _v_c = 1, #_v_objects do
	if (Page.GetPluginObjectPtr(_v_objects[_v_c]) == 666) then 
		return _v_objects[_v_c] 
	end
end
return nil
As we know the plugin ptr, we could get the name with this stub, that translates to C in this code:
static int luacee_ptrtoname_pushstring(lua_State * L, DWORD ptr) {
	enum { lc_nformalargs = 0 };
	const int lc_nactualargs = lua_gettop(L);
	const int lc_nextra = (lc_nactualargs - lc_nformalargs);

	/* local _v_objects = Page.EnumerateObjects() */
	lua_getglobal(L, "Page");
	lua_pushliteral(L, "EnumerateObjects");
	lua_gettable(L, -2);
	lua_remove(L, -2);
	lua_call(L, 0, 1);
	//assert(lua_gettop(L) - lc_nextra == 1);

	/* for _v_c = 1, #_v_objects do */
	lua_pushnumber(L, 1);
	const double lc4 = lua_objlen(L, (1 + lc_nextra));
	lua_pushnumber(L, lc4);
	if (!((lua_isnumber(L, -2) && lua_isnumber(L, -1)))) {
		luaL_error(L, "'for' limit must be a number");
	}
	double lc1_var = lua_tonumber(L, -2);
	const double lc2_limit = lua_tonumber(L, -1);
	const double lc3_step = 1;
	lua_pop(L, 2);
	enum { lc5 = 1 };
	while ((((lc3_step > 0) && (lc1_var <= lc2_limit)) || ((lc3_step <= 0) && (lc1_var >= lc2_limit)))) {

		/* internal: local _v_c at index 2 */
		lua_pushnumber(L, lc1_var);

		/* if (Page.GetPluginObjectPtr(_v_objects[_v_c]) == 666) then */
		enum { lc6 = 2 };
		lua_getglobal(L, "Page");
		lua_pushliteral(L, "GetPluginObjectPtr");
		lua_gettable(L, -2);
		lua_remove(L, -2);
		lua_pushvalue(L, (2 + lc_nextra));
		lua_gettable(L, (1 + lc_nextra));
		lua_call(L, 1, 1);
		lua_pushnumber(L, ptr);
		const int lc7 = lua_equal(L, -2, -1);
		lua_pop(L, 2);
		lua_pushboolean(L, lc7);
		const int lc8 = lua_toboolean(L, -1);
		lua_pop(L, 1);
		if (lc8) {

			/* return _v_objects[_v_c] */
			lua_pushvalue(L, (2 + lc_nextra));
			lua_gettable(L, (1 + lc_nextra));
			return 1;
			//assert(lua_gettop(L) - lc_nextra == 2);
		}
		lua_settop(L, (lc6 + lc_nextra));
		//assert(lua_gettop(L) - lc_nextra == 2);

		/* internal: stack cleanup on scope exit */
		lua_pop(L, 1);
		lc1_var += lc3_step;
	}
	lua_settop(L, (lc5 + lc_nextra));
	//assert(lua_gettop(L) - lc_nextra == 1);

	/* return nil */
	lua_pushnil(L);
	return 1;
	//assert(lua_gettop(L) - lc_nextra == 1);
}

static const char* luax_ptr2name(lua_State* L, CIRPluginObject* ptr) {
	luacee_ptrtoname_pushstring(L, (DWORD)ptr);
	return lua_tostring(L, -1);
}
So we can now call luax_ptr2name(L,this) to get the assigned name, so lets add a new CodeEvent method:

.h
	lua_State* m_pLuaState;
	void CodeEvent(LPCTSTR strEventName);
	char* plugin_name;
.cpp
void CIRPluginObject::CodeEvent(LPCTSTR strEventName)
{
	if (!m_pLuaState) return;
	if (strlen(plugin_name)==0) 
		plugin_name = strdup(luax_ptr2name(m_pLuaState, this));
	lua_getglobal(m_pLuaState, "Page");
	lua_pushstring(m_pLuaState, "GetObjectScript");
	lua_gettable(m_pLuaState, -2);
	lua_remove(m_pLuaState, -2);
	if (lua_isfunction(m_pLuaState, -1)) {
		lua_pushstring(m_pLuaState, plugin_name);
		lua_pushstring(m_pLuaState, strEventName);
		if (lua_pcall(m_pLuaState, 2, 1, 0) != 0) {
			// Error
			lua_remove(m_pLuaState, -1);
			return;
		}
		if (!lua_isstring(m_pLuaState, -1)) {
			lua_remove(m_pLuaState, -1);
			return;
		}
		const char* code = lua_tostring(m_pLuaState, -1);
		if (strlen(code) > 0) {
			lua_pushstring(m_pLuaState, plugin_name);
			lua_setglobal(m_pLuaState, "this");
			luaL_dostring(m_pLuaState, code);
		}
		lua_pop(m_pLuaState, lua_gettop(m_pLuaState));
	} else {
		lua_remove(m_pLuaState, -1);
		return;
	}
}
This is an example of how to use the code but could be extended if other needs appear, like capacity of returning, which is principally why ive got this approach.
:beta: :beta:

muchas gracias
Siempre es un placer estudiar tus novedades
So wonderful...Excellent :friends: