Что нового

[Баг] Крах скрипта при использований DllCallbackFree из callback функции

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 124
Репутация
2 322
Пример:

Код:
$hTimer = __TCPInet_SetTimer('test')

Sleep(1000)

Func test($hWnd, $iMsg, $iIDTimer, $dwTime)
	ConsoleWrite($iIDTimer & @LF)
	__TCPInet_KillTimer($hTimer, $iIDTimer)
EndFunc

Func __TCPInet_SetTimer($sTimerFunc, $iElapse = 250)
	Local $hCallBack = 0, $pTimerFunc = 0, $aResult
	
	$hCallBack = DllCallbackRegister($sTimerFunc, 'none', 'hwnd;int;uint_ptr;dword')
	$pTimerFunc = DllCallbackGetPtr($hCallBack)
	
	If $hCallBack = 0 Or $pTimerFunc = 0 Then
		Return SetError(-1, -1, 0)
	EndIf
	
	$aResult = DllCall('user32.dll', 'uint_ptr', 'SetTimer', 'hwnd', 0, 'uint_ptr', 1001, 'uint', $iElapse, 'ptr', $pTimerFunc)
	
	If @error Or $aResult[0] = 0 Then
		DllCallbackFree($hCallBack)
		Return SetError(@error, @extended, 0)
	EndIf
	
	Return $hCallBack
EndFunc

Func __TCPInet_KillTimer($hTimer, $iIDTimer)
	DllCall('user32.dll', 'bool', 'KillTimer', 'hwnd', 0, 'uint_ptr', $iIDTimer)
	DllCallbackFree($hTimer) ;Причина падения
EndFunc


Скрипт валится если использовать __TCPInet_KillTimer из функции вызова (test()).
Проверено на версий 3.3.10.2.

Я понимаю что не совсем правильно закрывать callback из него самого же, но всё таки, я думаю скрипт не должен падать...

С AdlibRegister такого не происходит:

Код:
AdlibRegister('test')

Sleep(1000)

Func test()
	Local Static $iCall = 0
	
	$iCall += 1
	
	ConsoleWrite('Call #' & $iCall & @LF)
	AdlibUnRegister('test')
EndFunc
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 318
CreatoR,
v3.3.8.1 и v3.3.13.19 у меня Ваш код нормально отрабатывает (WinXP 32).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 702
CreatoR сказал(а):
Я понимаю что не совсем правильно закрывать callback из него самого же, но всё таки, я думаю скрипт не должен падать...
Тоесть уничтожать объект, когда он еще используется, это "не совсем правильно"? К слову, у меня тоже не вылетает скрипт, но тем не менее так делать категорически нельзя. А кроме того, зачем тебе освобождать callback, если его код постоянный? Достаточно один раз при старте скрипта вызвать DllCallbackRegister() и забыть про него. Его даже при выходе можно не освобождать, главное, чтобы отвязать его от всех функций. В данном случае достаточно вызвать KillTimer().

Код:
If $hCallBack = 0 Or $pTimerFunc = 0 Then
	Return SetError(-1, -1, 0)
EndIf


Здесь не нужно делать проверку, т.к. ошибка может произойти только, если неправильно указать имя функции.

Код:
Return SetError(@error, @extended, 0)


Как же меня раздражает jpm, пишет то, что сам не понимает. Вот этими тупыми выражениями, он исказил весь смысл WinAPIEx UDF. Именно поэтому я и использую до сих пор 3.3.8.1.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 124
Репутация
2 322
Стоит ли создать тикет по теме?
 

firex

AutoIT Гуру
Сообщения
943
Репутация
203
CreatoR
А есть смысл?

Уничтожите объект > вызываться он не будет(должен), иначе - крах > раз он не вызывается, то какой смысл в "уничтожении"?

P.S. У меня отрабатывает без вылета.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 124
Репутация
2 322
Я считаю что так быть не должно, скрипт не должен крашится ни при каких обстоятельствах.

Кстати, крашится он из за x64, добавляем в начало:
Код:
#AutoIt3Wrapper_UseX64=n

и скрипт не крашится :smile:.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 702
CreatoR сказал(а):
Я считаю что так быть не должно, скрипт не должен крашится ни при каких обстоятельствах.
Крах скрипта в данном случае вполне логичен, а вот то, что в некоторых случаях пример отрабатывает нормально, это можно отнести к издержкам AutoIt. После того, как ты вызвал DllCallbackFree(), соответствующей функции считай не существует. Это тоже самое, что попытаться выгрузить DLL из самого себя.
 
Верх