Re: BREAKing into Euphoria

new topic     » goto parent     » topic index » view thread      » older message » newer message

An update. Dont mind the cd lib stuff. Shows usage of iupmglplot. Also shows how to drastically reduce IUP message polling CPU by reduced polling during idleness.

 
with define DEBUG_TYPE	--popup debugger after type check failures otherwise comment out for the normal crash 
 
include euphoria/debug/debug.e 
include std/math.e 
include std/console.e 
include std/os.e 
--include dll.e 
--include machine.e 
 
include gui/iup/iup.e 
include gui/iup/iup_config.e 
include gui/iup/iup_mglplot.e 
/* 

include gui/iup/cd.e 
include gui/iup/cdiup.e 
*/ 
 
 
constant user32 = open_dll( "user32" ) 
constant xSetForegroundWindow = define_c_func( user32, "SetForegroundWindow", {C_ULONG}, C_UINT	) -- BOOL SetForegroundWindow(HWND) 
constant xGetForegroundWindow = define_c_func( user32, "GetForegroundWindow", {}, C_UINT	) -- HWND GetForegroundWindow(void) 
atom focusOld=0		 --start with NULL (invalid) 
atom debugTime=0 
 
procedure traceOn(integer val) 
	poke4(0x5b1a20, val)	 --ie TraceOn=val 
	poke4(0x5b1440, 1)		 --color_trace = TRUE;	--ie ensures the debugger pops up in color (not static uninit value of 0 ie B/W) 
end procedure 
 
 
global procedure goDebug(integer focusDebug)	--go to the debugger at the next trac'able line 
	focusOld=c_func(xGetForegroundWindow)		--save the current focus'ed win handle 
	debugTime=time() 
	if focusDebug then 
		c_func(xSetForegroundWindow, {hCon} ) 
	else	-- don't want to set focus to debugger; ie waiting for some iup gui user activity to enter trace'able code, so 
	end if				--switch to (debugger) console window 
	traceOn(1)		--TraceOn=1 ie trace out to the debugger at next "with trace" code. 
end procedure 
 
global procedure tr(object condition={}, sequence errorMessage={}) 
--atom condition <> 0, then print errorMessage, else ignore. Eg tr(1>0, {"%s %d", "five=", 5}) 
--string 'condition' for simple error message 
	if atom(condition) and condition = 0 then return end if				 --failed condition if its numeric 
	if length(errorMessage) >= 2 and sequence(errorMessage[1]) then	--formatting string, args ... 
			errorMessage=sprintf(errorMessage[1], errorMessage[2..$]) 
	end if 
	if atom(condition) then 
		condition=sprintf("%d", condition) 
	elsif length(condition) then 
		errorMessage=sprintf("%s %s", {condition, errorMessage}) 
		condition="" 
	end if 
	if length(errorMessage) or length(condition) then --non-empty string, so elaborate error 
		printf(1, "\ntr(%s): %s\n", {condition, errorMessage}) 
	end if 
	goDebug(1) 
end procedure 
 
 
 
atom breakTime=0 
 
function breakFunc(integer event) 
	puts(1, "Break pressed... ") 
	breakTime -= time() 
	if breakTime > -1	then 
		traceOn(0)	--cancel trace out to debugger (set first press), so terminate immediately 
		puts(1, "quick break repeat; exiting app...\n") 
		return 0		--Quickly repeated break, so act as if break not handled by this fn, ie pass on to next handler (eu terminates) 
	end if 
	breakTime = time()		--update timestamp 
	goDebug(1) 
	return 1	--handled the control signal so return TRUE for no further action. 
end function 
 
 
 
without trace		--we dont trace inside type checks 
ifdef DEBUG_TYPE then	 -- pinpoints the type error location with the debugger 
	function typeEnd() 
			goDebug(1)		--popup the debugger at the next traceable line 
			return 1			--no type abort; continue running 
	end function 
elsedef 
	function typeEnd() 
		return 0	--abort with type check error 
	end function 
end ifdef 
 
 
type Ihandle(atom x) 
	if x>NULL then	--ok positive 
		if trunc(x) = x then return 1 end if		 --no fractional part so x ok so continue running 
	end if 
	printf(1, "type Ihandle: bad value %d\n", {x}) 
	return typeEnd() 
end type 
 
type cdCanvas(atom x) 
	if x>NULL then	--ok positive 
		if trunc(x) = x then return 1 end if		 --no fractional part so x ok so continue running 
	end if 
	printf(1, "type cdCanvas: bad value %d\n", {x}) 
	return typeEnd() 
end type 
 
type cdContext(atom x) 
	if x>NULL then	--ok positive 
		if trunc(x) = x then return 1 end if		 --no fractional part so x ok so continue running 
	end if 
	printf(1, "type cdContext: bad value %d\n", {x}) 
	return typeEnd() 
end type 
 
with trace 
 
Ihandle plot 
 
 
function k_any( Ihandle self, atom c ) 
	tr(c='q', {"Debugging IUP client callback, c=%d", c}) 
	return IUP_DEFAULT 
--	return IUP_IGNORE 
end function 
 
function action( Ihandle self, integer c, atom after ) 
	if (c) then 
	end if 
	return K_asterisk 
end function 
 
--atom kernel32, xSetConsoleCtrlHandler, cbHR 
atom xSetConsoleCtrlHandler, cbHR 
 
 
procedure noIup() 
	integer key 
	while 1 do 
		puts(1,"sleeping press q to quit, break to debug\n") 
		sleep(2) 
		key=get_key() 
		printf(1,"awake, key=%d\n", {key}) 
		if key = 'q' then 
			exit 
		end if 
	end while 
end procedure 
 
 
 
function iupStart( object argc, object argv ) 
	IupOpen( argc, argv ) 
 
	IupMglPlotOpen()    --init IupMGLPlot library 
	plot = IupMglPlot()		--creates a empty initial data set 
	IupMglPlotBegin(plot,2) 
	for i=1 to 70 do 
		IupMglPlotAdd2D(plot, i, i*i) 
	end for 
	{}=IupMglPlotEnd(plot)		--puts the plot data into _plot. Now we can use IupSetAttribute() to modify plot data 
--	IupSetAttribute(text, "SIZE",	"200x") 
--	IupSetCallback(text, "ACTION", Icallback("action")) 
--	IupSetCallback(text, "K_ANY", Icallback("k_any")) 
	--IupSetAttribute(plot, "AXS_X", "NO")	--ok 
	--IupSetAttribute(plot, "LEGEND", "YES")	--ok 
	--IupSetAttribute(plot, "GRID", "XY")	--ok 
	IupSetAttribute(plot, "DS_COLOR", "255 0 255")	--ok  "R G B" 
	IupSetAttribute(plot, "DS_MODE", "BAR")	--ok 
	IupSetAttribute(plot, "REDRAW", NULL) 
 
/* 

	Ihandle iCanvas = IupCanvas()		--Ihandle *cnvs 
--		cdcanvas = cdCreateCanvas( CD_IUP, cnvs );	--static cdCanvas *cdcanvas .   H:\dl\graphics\CanvasDraw\v5.9\cd-5.9_Sources.zip;cd\include\cd.h;  cdCreateCanvas(cdContext *context, void *data); 
	cdContext ctx=CD_IUP() 
	cdCanvas canvas = cdCreateCanvas(ctx, iCanvas )	--static cdCanvas *cdcanvas .   H:\dl\graphics\CanvasDraw\v5.9\cd-5.9_Sources.zip;cd\include\cd.h;  cdCreateCanvas(cdContext *context, void *data); 
	cdCanvasForeground(canvas, CD_BLUE) 
--	cdCanvasLineWidth(canvas, 3); 
--	cdCanvasLineStyle(canvas, CD_CONTINUOUS); 
	cdCanvasRect(canvas, 0, 200, 0, 200) 
--	cdKillCanvas(canvas) 
	--	IupMglPlotNewDataSet(plot, 2)	--create another data set 
*/ 
 
	Ihandle dlg = IupDialog(plot)	--create a dialogue element to put the plot into 
	IupSetAttributes(dlg, "RASTERSIZE=640x480") 
	IupSetAttribute(dlg, "TITLE", "temperature/moisture") 
 
--	IupSetAttribute(plot, "GRID=YES, MARGINBOTTOM=80, AXS_XTICKROTATENUMBER=YES, MARGINRIGHT=80") 
--	IupSetAttribute(plot, "READONLY", "NO") 
--    IupSetAttribute(dlg, "MARGIN", "100x100") 
 
	IupShowXY(dlg, IUP_CENTER, IUP_CENTER) 
	return EXIT_SUCCESS 
end function 
 
without trace	 --we dont want to debug iupIdle or the iup event polling loop 
atom idleSleep=0 
function iupIdle() 
	idleSleep=.11	--iup is idle so increase the polling delay 
	return IUP_DEFAULT 
end function 
 
constant kernel32 = open_dll( "kernel32.dll" ) 
constant xGetConsoleWindow = define_c_func( kernel32, "GetConsoleWindow", {}, C_ULONG ) 
atom hCon = c_func( xGetConsoleWindow, {} ), hIup=0, hCurrent=0 
 
constant xGetNumberOfConsoleInputEvents = define_c_func( kernel32, "GetNumberOfConsoleInputEvents", {C_ULONG , C_POINTER}, C_INT) 
	--HANDLE hConsoleInput, _Out_	LPDWORD lpNumberOfEventsRead 
constant dwordVar = allocate(4) 
 
------------------ CONSOLE INPUT FNs 
integer xReadConsoleInput = define_c_func( kernel32, "ReadConsoleInputW", {C_ULONG , C_ULONG, C_INT, C_POINTER}, C_INT) 
	--HANDLE hConsoleInput, _Out_	PINPUT_RECORD lpBuffer, _In_	 DWORD nLength, _Out_	LPDWORD lpNumberOfEventsRead 
if xReadConsoleInput = -1 then	-- Using "ReadConsoleInput" doesnt work, so we try this for the failed explicit "ReadConsoleInputW" 
	xReadConsoleInput = define_c_func( kernel32, "ReadConsoleInputA", {C_ULONG , C_ULONG, C_INT, C_POINTER}, C_INT) 
end if 
constant ptrInputRecord = allocate(24)	--mem block for a single INPUT_RECORD 
 
constant KEY_EVENT=1		 --EventType is a key press/release 
constant MENU_EVENT=8 
constant FOCUS_EVENT=16 
-- INPUT_RECORD typedef; abs address of record members in ptrInputRecord (ie includes +offset) 
constant EventType = ptrInputRecord+0 
	-- KEY_EVENT union; 
	constant bKeyDown=ptrInputRecord+4 
	constant wRepeatCount=ptrInputRecord+8 
	constant wVirtualKeyCode=ptrInputRecord+10 
	constant wVirtualScanCode=ptrInputRecord+12 
	constant AsciiChar=ptrInputRecord+14 
	constant dwControlKeyState=ptrInputRecord+16 
------------------ 
 
 
constant xGetStdHandle= define_c_func( kernel32, "GetStdHandle", {C_INT}, C_ULONG) 
constant hConsoleInput=c_func(xGetStdHandle, {-10} )	-- -10 = STD_INPUT_HANDLE 
if hConsoleInput = -1 then ?9/0 end if 
 
--BOOL SetConsoleTitle(char *lpConsoleTitle)		--Kernel32 
-- see	H:\dl\c\win32\console API.pdf	 EVENT_CONSOLE_CARET	 callback event . 
-- H:\dl\c\win32\WinEvents API.pdf	p608 
 
sequence cmd = command_line() 
sequence argv = cmd[3..$] 
integer argc = length( argv ), iuret 
 
 
xSetConsoleCtrlHandler = define_c_func(kernel32,"SetConsoleCtrlHandler", 
		{C_POINTER, --	PHANDLER_ROUTINE	pHandlerRoutine,	// address of handler function 
		C_INT},		--	BOOL	fAdd	// handler to add or remove 
		C_INT)			-- BOOL 
 
cbHR = call_back(routine_id("breakFunc"))	 --{’+’, id} for cdecl 
if not c_func(xSetConsoleCtrlHandler,{cbHR,1}) then ?9/0 end if 
 
--noIup()		 --test interrupting a console (without iup) loop with async break key. 
 
iupStart( argc, argv ) 
 
IupSetGlobalFunction("IDLE_ACTION", Icallback("iupIdle"))	 --iup will call this idle callback so we can flag when iup is idle and reduce polling freq 
 
--	IupMainLoop()	 --blocks this foreground process until user closes GUI 
loop do		 --iup event polling loop 
	printf(1, "Press break to debug ") 
	? idleSleep & hCon & hIup & hCurrent & date() 
	sleep(idleSleep) 
	----- peek into the keyboard queue for debugger keyboard code sent from external app (NB: we dont use get_key() because onTrace=1 which will cause long delays until the next tracable line occurs and the debugger starts) 
	if not c_func(xGetNumberOfConsoleInputEvents, {hConsoleInput, dwordVar} )	then ?9/0 end if 
	for i = 1 to peek4s(dwordVar) do	--read each event (if > 0) 
		{}=getKey() 
	end for 
	----- 
	hCurrent=c_func(xGetForegroundWindow) 
	if hCurrent != hCon then 
		hIup=hCurrent 
	end if 
	if focusOld then	--old window focus before debugger invoked 
		if focusOld = hCon then focusOld=hIup end if	--debugging IUP window, so reject hCon 
		if focusOld != hCurrent and time()-debugTime > 0.3 then 
			--old windows not focussed and been some time (stuck in the debugger outside this block) since debugTime updated. 
			{}=c_func(xSetForegroundWindow, {focusOld} )	--focus the old windows 
			focusOld =0	 --and finnished refocusing old window, so invalidate (NULL) 
		end if 
		debugTime=time()		--update time last in this block 
	end if 
	idleSleep=.01			--do a short sleep for good user interaction speed, unless iup becomes idle and calls iupIdle() which will set a longer sleep to reduce CPU wastage 
	--IupSetAttribute(plot, "REDRAW", NULL) 
	until IupLoopStep() = IUP_CLOSE	-- poll and execute next iup event (if any). This will also call iupIdle() if iup gui event queue is idle 
end loop 
IupClose() 
 
function getKey()	--get_key() replacement, that doesnt pause 
	if not c_func(xReadConsoleInput, {hConsoleInput , ptrInputRecord, 1, dwordVar})	then ?9/0 end if	--read 1 INPUT_RECORD event, NULL to store # events read. 
	-- *dwordVar stores the address of the win32 provided input record buffer 
	if peek2u(EventType) != KEY_EVENT	or not peek(bKeyDown) then				 ----ignore non-key events or key up events 
		return -1 
	end if 
	integer ch=peek(AsciiChar) 
	if ch = 3 then		 --external global 'Alt-Break' Autohotkey script attached to our console and sent break key (useful since we dont loose gui focus) 
		goDebug(1) 
	elsif ch = 0 then		 --a control key 
		return -1	 --ignore 
	end if 
--	? ch 
	return ch 
end function 
 
new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu