Что нового

Вариант безопасного Callback в ваших UDF

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Вы пишите функцию, которая в качестве параметра принимает имя пользовательской функции для callback`а, т.е выполнив какие то действия, ваша функция должна вызвать другую функцию.
Обычно это делается через Call, например
Код:
Call($userF)

Но тут сразу есть неприятный момент, сразу после вызова Call, скрипт начинает выполнять другую функцию, а ваша остается не завершенной и ждет, пока завершится вызванная функция.
Второй неприятный момент в том, что вы не можете знать, что сделает функция пользователя, вдруг там будет очередной вызов вашей функции, тут и глядишь, дело дойдет и до рекурсии.

Избавиться от этого можно через AdlibRegister.
Например:
Код:
Global $__unregF
Func udf($userF)
	$__unregF = $userF
	AdlibRegister($__unregF,5)
	AdlibRegister('__unregF',5)
EndFunc
Func __unregF()
	AdlibUnRegister($__unregF)
	AdlibUnRegister('__unregF')
EndFunc

Здесь udf ваша функция, принимающая первым параметром имя другой функции.

Как это работает:
Два подряд AdlibRegister c одинаковыми временами выполнятся последовательно, первый выполнит функцию пользователя, второй - свою собственную.
Своя собственная, начав выполняться, де регистрирует себя и функцию пользователя. Вот и весь трюк.

Небольшой пример:
Код:
Global $__unregF
udf('userf')
While 1
	Sleep(100)
WEnd
Func userf()
	ConsoleWrite('> Callback' & @LF)
	udf('userf')
EndFunc
Func udf($userF)
	$__unregF = $userF
	AdlibRegister($__unregF,5)
	AdlibRegister('__unregF',5)
EndFunc
Func __unregF()
	AdlibUnRegister($__unregF)
	AdlibUnRegister('__unregF')
EndFunc


Если бы в udf был вызов через Call, то скрипт завершился бы с критической ошибкой AutoIt will quit to prevent stack overflow..
А в данном случае этого не происходит.
 

MnM

Post-Hardcore
Сообщения
679
Репутация
90
inververs
А можно вариант в котором выражется "небезопасный вызов", в котором явны будут последствия? :smile:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Вот более практичный пример, где можно указывать параметры для пользовательской функции:

Код:
Global $aMyUDF_Data[2]
Global $sFuncCaller = '_FuncCaller'

_MyUDF('_UserFunc', 'Start Function')

Sleep(1000)

Func _UserFunc($vParams)
	Static $iCount
	
	If $iCount = 10 Then
		ConsoleWrite('End Function' & @LF)
		Return
	EndIf
	
	ConsoleWrite($vParams & @LF)
	_MyUDF('_UserFunc', 'Some other params')
	
	$iCount += 1
EndFunc

Func _MyUDF($sUserFunc, $vParams = '')
	;....
	
	$aMyUDF_Data[0] = $sUserFunc
	$aMyUDF_Data[1] = $vParams
	
	AdlibRegister($sFuncCaller, 5)
EndFunc

Func _FuncCaller()
	AdlibUnRegister($sFuncCaller)
	Call($aMyUDF_Data[0], $aMyUDF_Data[1])
EndFunc
 
Верх