Что нового

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

CreatoR

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

Код:
$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,322
CreatoR,
v3.3.8.1 и v3.3.13.19 у меня Ваш код нормально отрабатывает (WinXP 32).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
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,671
Репутация
2,481
Стоит ли создать тикет по теме?
 

firex

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

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

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

CreatoR

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

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

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

Yashied

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

Крах скрипта в данном случае вполне логичен, а вот то, что в некоторых случаях пример отрабатывает нормально, это можно отнести к издержкам AutoIt. После того, как ты вызвал DllCallbackFree(), соответствующей функции считай не существует. Это тоже самое, что попытаться выгрузить DLL из самого себя.
 
Верх