Control de excepciones en AMS - LUA

Aquí puedes preguntar o compartir tus dudas y conocimientos acerca del programa
Hola, no he buscado mucho pero se me vino a la cabeza ahora que veo el tipico Mensaje de AMS cuando hay un error...

¿Hay alguna forma de controlar excepciones en AMS? que no sea el pobre:
-- Test for error
error = Application.GetLastError();
if (error ~= 0) then
	Dialog.Message("Error", _tblErrorMessages[error], MB_OK, MB_ICONEXCLAMATION);
end
¿Alguien tiene otra solucion?

Pues veras viejo, lo de menos seria que te crees una dll con todos los errores y los manejes a tu modo, pero como se que esta cabron porque es muy cansado la unica solucion que te puedo dar es:

Que crees tu propio error (Dialog.Message()) y que termines la app con un Application.ExitScript()... Claro que para lo anterior deberias de comenzar por identificar todos los posibles errores mediante condiciones y demas que se te ocurra dentro de los cuales podria caer un jodido error.

Asi lo hago en los plugins que he realizado, hago "filtros" lo mas logicos posibles, de esta manera me anticipo al putoperrocagado sistema antiestetico todo feo de mierda de errores del ams :sorry: :) :) :) bueno, cuando andaba ahi, ahora ando en el cielo LOL y ya no tengo tiempo para entrar al ams, cuando menos en # hay un poco mas de seguridad.
Saludos ;)

Haber controlar la ejecución de lua no es dificil hay un par de funciones que pueden ayudar:

Código: Seleccionar todo

pcall(somefunction,[arg1,arg2,arg3]) -> protected call
assert(somefunction,[errormsg]) -> if not nil or false
Teniendo esto claro puedes tener una funcion por ejemplo
function lol(x,y)
       error loco aqui;
       return x+y
end
podrias ejecutar esta funcion aislada de esta manera:
err,msg=pcall(lol,1,2)
fail=assert(err,msg)

Gracias metanfuken, hago lo mismo que tu para controlar los errores de AMS pero me parece poco práctico, los errores los puedo sacar de la tabla de errores pero lo que quiero es exactamente "catch the excepction" de este modo supongo no aparecería el error mensaje de error típico que aunque es útil para el que programa, no es debido que se muestre en una aplicación terminada.

Lo que busco es que esto no aparezca, pensaba que usando try catch podía solucionarlo pero LUA no tiene try catch :(

La opción de Pabloko realmente controla el error, pero como con otras opciones sigue apareciendo el mensaje....

Imagen

Aqui dejo algunas referencias para los que quieran utilizar try catch con LUA:

HIDE: ON
Hidebb Message Hidden Description

Cambio el titulo del tema de "Excepciones en AMS" a "Control de excepciones en AMS - LUA"

in ams help file some error numbers how the autoplay is know it or by pabloko is talking

Muchas gracias.

estoy liado con este tema, echando un vistazo

Veo que el problema para la opcion de pabloko es del mismo ams.

La forma que dices tu Thedary seria asi no?

Funciones Globales:
function catch(what)
	return what[1]
end

function try(what)
	status, result = pcall(what[1])
 	if not status then
             what[2](result)
	 end
	return result
end

function UnaFuncionCualquiera()
	try{
		function()
			a = b[1]--Este es el error fatal, b no ha sido creado.
		end,
		
		catch {
			function(error)
				
				error = string.gsub(error, "%[.+%]%:", "");
				errormess = "Localizado en: " .. Debug.GetEventContext() .. "\r\nError# " ..error;
				LogAms.Add("error",errormess); --Escribir el error al log
				Dialog.Message("Error", errormess, MB_OK, MB_ICONSTOP, MB_DEFBUTTON3); --Presentarlo para cuando estamos mirando.
			end
			}
		}
end
Desde un boton por ejemplo.
UnaFuncionCualquiera();

De esta manera tambien me funciona y para mi gusto es mas sencilla.

Creamos una funcion donde pasaremos la cadena de error para que sea tratada y presentada.
function logerror (error)
	local error = string.gsub(error, "%[.+%]%:", ""); --Limpio caracteres
	local errormess = "Localizado en: " .. Debug.GetEventContext() .. "\r\nError# " ..error; --Preparo la linea de error que quiero presentar
	LogAms.Add("error",errormess); --Escribir el error al log 
	Dialog.Message("Error", errormess, MB_OK, MB_ICONSTOP, MB_DEFBUTTON3); --Presentarlo por pantalla cuando estamos debugueando la aplicacion.
	collectgarbage(); 
	Application.ExitScript(); --Esta sentencia se puede eliminar, yo la tengo para asegurar que el error no se propague. 
end
Ahora para este ejemplo creamos una funcion global o local como quieran.
function unacualquiera(a,b)
	 a = b[1]--Este es el error fatal para el ajemplo, b no es de tipo tabla.
	 return a + b
end
Ahora vamos a ver como llamar a esta funcion,
Para llamar a la funcion usamos pcall como ya lo han dicho antes:
--[[ Usamos pcall el primer valor la funcion sin (), y despues los argumentos que podemos pasarle a esta funcion.
Si la funcion se realiza sin errores el status sera true y el mensaje sera la devolucion de la funcion si existe, en nuestro caso la suma de los dos argumentos.
Si la funcion contiene errores entonces devolvera false y el mensaje de error.
--]]
local status, mensaje = pcall(unacualquiera,1,2) 
if not status then
	logerror(mensaje); --Pasamos el error a la funcion que creamos para tratar el mensaje.
else
	Dialog.Message("Notice", mensaje, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1); --Presentamos el resultado de esa funcion.
end
Creo que esta puede ser una buena manera.
Otro Ejemplo:

Implementado en todo On Show
local On_Show = function()
	 --[[ Escribiremos de forma normal cualquier error producido aui sera pasado a nuestra funcion logerror --]]
	 
	 if a == b[1] then
	 	-- Un grave error
	 else
	 	unacualquiera(a,b) --Llamamos a una funcion sin argumentos
	 end
end



local status, mensaje = pcall(On_Show)
if not status then
	logerror(mensaje);
else
	Dialog.Message("Modo debug","On_Show Lanzado sin errores", MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
end

Ciertamente terminé usando pcall, pero no habia visto tu ejemplo. :yes:

Muy util, me va a servir mucho, gracias tairorojo.

Hace rato no veia a alguien que le gustara LUA por aca :)

Buenas thedary, me gusta ams porque creo que no esta mal la rapidez de creacion de aplicaciones, el lenguaje lua, creo que es sencillo y rapido una ves tienes claro su verdadero uso, ahora mismo estoy trabajando en dar mas "seguridad" a los proyectos ams, no para que no pueda ser copiados o duplicados, para eso ya hay muchas implementaciones, sino para que no puedan extraernos el codigo de nuestra aplicacion sacando por ejemplo nuestros password usuarios etc.

Yo uso esta manera de trabajar y voy añadiendo en la funcion error los valores localizados y los porques si estan controlados.

De echo gracias a esta forma, he conseguido identificar porque siempre se rompe la aplicacion con el "appcrash" windows 7 y superiores cuando utilizas cualquier loop reiterativo grande o alguna pausa elevada reiterativa.

Bueno este es otro tema, un saludo.

Lo que dejaste me sirvio mucho, hasta ahora no me habia sentado a pensar como iba a controlar el log pero era fácil.

La función le da formato al mensaje y lo lleva a un archivo de texto plano para que pueda ser consultado luego, los mensajes se verían de la siguiente manera:

Código: Seleccionar todo

Hora: 02/13/14 10:36:17
Error en: PEEKMI -> dev_button -> On Click
...uments and Settings\Clara\Escritorio\peekmi\test.lua:5: attempt to index global 'bryant' (a nil value)

Hora: 02/13/14 10:45:32
Error en: PEEKMI -> dev_button -> On Click
PEEKMI -> dev_button -> On Click, Line 4: 
Cuando son errores de funciones de AMS, no sale el mensaje de error, solo la ruta donde está (todavia falta...) y los errores de sintaxis los sigue recogiendo AMS.
function errorlog(b)
   local a,f = "Error en: ", "pm_errors.log"
   
   if _IR_ProductID then -- Verificamos si estamos ejecutando AMS asi evitamos errores al usar la funcion en lua puro
     a = a..Debug.GetEventContext().."\n"
   end
   
   local file = io.open(f, "a+")
   
   if not file then
     file = io.output(f)
   end
   
   file:setvbuf("no") -- Desactivamos el buffering; the result of any output operation appears immediately. 
   c = "Hora: "..os.date("%c") 
   d = "\n"..a..b.."\n"..Application.GetLastError().."\n\n"
   file:write(c..d)
   -- Pienso que es mejor no cerrar el archivo de logs para que en ejecución solo sea modificado por la aplicación, sin embargo...
   print(c..d)
   file:close()
end
Asi se usa:
exec, emsg = pcall(f)

if not exec then
   local log = logerror(emsg)
   if log then
      Dialog.Message("Error", log, 0,16,512)
   end
else
   -- Ejecución correcta
end
Ya puedo imaginar que es lo que estás utilizando para proteger tus scripts lua, pero me gustaría saber que fue lo que descubriste con los loops en Windows 7.

Saludos y gracias.

@tairorojo este codigo

https://gist.github.com/cwarden/1207556 ... 6a52b1fe9d

solo te permite integrar un argumento, ademas es posible que controle errores de ejecucion, pero errores de forma o corrupcion de datos te los va a seguir enviando por msgbox

el runtime de ams tiene mas o menos este codigo

lua_getglobal(L,"onStartup");
lua_pushstring(L,cmdplg);
if(lua_pcall(L,1,0,0)!= 0)
{ MessageBox(NULL, lua_tostring(L, -1), "AutoPlay Runtime",MB_OK); }


Lo más sencillo en este punto es editar los binarios de lua 5.1.4 y editar la funcion pcall para omitir la salida de errores, luego solo sustituir el archivo lua51.dll del proyecto y ya está, pero en cierto punto esta chapuza ppuede dar problemas por otro sitio si algo no funciona bien o necesita esta funcionalidad de obtener errores en el stack

Desde luego estos mensajes vienen del runtime y solo se pueden quitar editandolo (o parcheandolo) o bien modificando el binario de lua

http://sourceforge.net/projects/luabina ... 20Sources/

archivo lapi.c

LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) {
struct CallS c;
int status;
ptrdiff_t func;
lua_lock(L);
api_checknelems(L, nargs+1);
checkresults(L, nargs, nresults);
if (errfunc == 0)
func = 0;
else {
StkId o = index2adr(L, errfunc);
api_checkvalidindex(L, o);
func = savestack(L, o);
}
c.func = L->top - (nargs+1); /* function to be called */
c.nresults = nresults;
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
adjustresults(L, nresults);
lua_unlock(L);
//return status;
return 0; //
//RETORNAMOS 0 POR LO QUE NO SE MOSTRARA NINGUNA VENTANA DE ERROR, PCALL SIEMPRE DEVUELVE 0!!!!!!!!!!!!!!!!!!!!!
}


Aqui te lo dejo ya compilado con vs2013
HIDE: ON
Hidebb Message Hidden Description


Si cambiais la dll de vuestro proyecto por esta ya no apareceran mas errores, pero no se que complicaciones podria dar esto en otros aspectos y aplicaciones mas complejas con componentes que usen pcall y necesiten obtener un retorno de error... haced vuestras pruebas

En cuanto a seguridad yo tengo mis propios sistemas para ocultar el codigo que desee, tablas sqlite y cosas asi, pero claro, no puedo desvelar mis metodos, aunque puedo decir que todo lo hago con una mezcla de cifrados pgp para encriptar con claves publicas, privadas y alteradores y un sistema muy ingenioso para generar la contraseña publica mediante un algoritmo privado de colocacion de funciones del programa que no tienen nada que ver, pero que ese propio codigo es un hash en si mismo, y que no puede reproducirse externamente intentando emular el mismo entorno o codigo.
otra modificacion que se puede hacer sobre la base es algo asi:

LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) {
struct CallS c;
int status;
ptrdiff_t func;
lua_lock(L);
api_checknelems(L, nargs+1);
checkresults(L, nargs, nresults);
if (errfunc == 0)
func = 0;
else {
StkId o = index2adr(L, errfunc);
api_checkvalidindex(L, o);
func = savestack(L, o);
}
c.func = L->top - (nargs+1); /* function to be called */
c.nresults = nresults;
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
adjustresults(L, nresults);
lua_unlock(L);

//pabloko error reporting
lua_getglobal(L, "DisplayErrors");
if (lua_isboolean(L, -1) && lua_toboolean(L, -1)==1) {
return 0;
}
else {
lua_pop(L, 1);
return status;
}

}


de esta forma comprobamos la variable DisplayErrors, deberemos iniciarla al comienzo de la aplicacion

Código: Seleccionar todo

DisplayErrors=false
tambien podemos reescribirla en cualquier punto de la ejecucion para evitar la salida de errores

Código: Seleccionar todo

DisplayErrors=false
...code...
DisplayErrors=true
compilado:
HIDE: ON
Hidebb Message Hidden Description

Muy interesante Pabloko, le voy a echar un vistazo, como siempre vas tres pasos por delante, en el proceso de seguridad yo estoy intentando realizar un "compilador" que nos de una seguridad ante rotura de codigo.

Es decir le vamos a pasar un proyecto ya terminado a la aplicacion, esta generara nuevos codigos encriptados y compilara el proyecto, quedando igual que siempre pero con la diferencia que una vez roto el codigo es decir abierto el ccd, solo vera las lineas comunes en todas las acciones, no el codigo en si.

Mi intencion es cuando este un poco mas que en fase Alpha subirlo aqui o en un Git para que podamos hacerlo entre todos.

Thedary mi conclusion final con los loop y el dichoso appcrash, primero lo de appcrash y lo de añadir el Dep. y esas cosas, para nosotros no nos vale, porque nosotros estamos programando para que trabaje con normalidad en windows y este appcrash lo que nos indica es que lo que le estamos dando no le gusta nada por ello nos dice que tu aplicacion ha echo "crash" (mejora tu puñetero codigo).

Cuando nos da este mensaje "appcrash" nuestro codigo sin estar mal literalmente es incompatible con windows, por ejemplo en los loop reiterativos grandes, debes poner una pausa de aplicacion (Application.Sleep(1)) "una estupidez que aun no entiendo" y asi windows no cree que la aplicacion a dejado de responder, y actualiza correctamente el sistema.

simplemente poned la primera dll que adjunto y adios a esos mensajes de error

Perdonadme, pero sin modificar la dll, como dice pabloko, tambien consigo eliminar los errores, un paso un ejemplo para que veais como.

De esta manera puedo trabajar en modo debug o en modo produccion.

https://mega.co.nz/#!4NYz0QhA!fSQd9upYo ... AOf72z_9JM


Porfavor echarle un vistazo, haber si es que estoy equivocado, y no veo algo que deberia ver.

Gracias.

En cuanto a lo que dices sobre los loops, nunca supe por qué pero termine agregando application.sleep(100) en los filecopycallbacks para que copiara todos los archivos correctamente o para que no se bloqueara.

Supongo que modificando el runtime como dice pablo tampoco saltarán los mensajes de error cuando haya errores de sintaxis, o me equivoco? lo digo porque de la forma que tairorojo planteó captura un error como este
a = {} 
b = a + 1
Pero no este:
a = {} 
b = a +)) 1

Disculpen pero estoy muy ocupado y por falta de tiempo no puedo probarlo

Realiza lo mismo, para crear ese mismo error he tenido que caragar el archivo loadstring, ya que si intentas escribir esa sentencia el mas no te deja por ver errores en la sintaxis, aunque esto si lo entiende.
a = {}
b = (a +  1)
El error lo trabaja igual.

Pero grabando en un archivo
a = {}
b = a +)) 1
Y lo cargo con loadstring quedando
--Colocamos la aplicacion en modo debug, ademas de indicarle que muestre los mensajes de errores.
seguridadDialogoError = "1";

-- Creamos una funcion en todo el evento por ejemplo  
local f = function()
	-- Colocamos error, intentamos leer un valor de una tabla que no existe.
	local l = loadstring(TextFile.ReadToString("AutoPlay\\Scripts\\codigo_con_error.lua"));
	l();
end

local status, mensaje = pcall(f); --despues lanzamos la funcion y si existe algun error lo pasamos sino se ejecuta normalmente.
if not status then
	logerror(mensaje);
end
Este error thedary no me vale y muchas gracias, cuando puedas echale un ojo al apz.