Что нового

Как правильно завершить работу скрипта?

musicstashall

Знающий
Сообщения
322
Репутация
7
Всем доброго.
В последних версиях Windows 10 система какбы «недоумевает» от неожиданной остановки скомпилированного скрипта и показывает вот такое сообщение: «Прекращена работа программы "Имя программы", Возникшая проблема привела к прекращению работы программы. Закройте эту программу.»

И как теперь нужно по-особенному закрывать программу? У меня выход реализован стандартно:
Код:
Func OnAutoItExit()
    Delete()
    If $hDLL Then DllClose($hDLL)
	_WinAPI_PostMessage(_WinAPI_FindWindow('AutoIt v3 GUI', "HostProc"), $GET_MESSAGE, -3, 0)
	SafeExit()
	Exit
EndFunc   ;==>OnAutoItExit
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
система останавливает программу , к примеру, утечка памяти.
вот это
Код:
If $hDLL Then DllClose($hDLL)

тоже может вызывать крах программы.
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
Попробовал без этого, всё равно так же.

Может это?

Код:
Func SafeExit()
    ConsoleWrite("exiting..." & @CRLF)
    DllCall("comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID)
    DllCallbackFree($psub)
EndFunc



Добавлено:
Сообщение автоматически объединено:

Так и получилось. Именно эта функция вызывала сбой. Но, если ее исключить, то скрипт вообще не завершается. Не выходит. :blink:
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Весь код приведи здесь. Я не пойму зачем такие сложности с выходом.
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
Весь код?? Сумасошел)) 4000 строк, может и больше. :laugh:

Delete() — закрытие фоновых окон
_WinAPI_PostMessage — сообщение другому процессу, чтобы тоже закрылся.
Ну а потом Exit.


Добавлено:
Сообщение автоматически объединено:

Видимо SafeExit надо закрывать, из-за нее и не выходит. Это реализация событий сообщений в трее.

Вот полный пример этой реализации:

Код:
#include <windowsconstants.au3>

Opt('TrayAutoPause', 0)
Opt('WinTitleMatchMode', 3)
Opt('WinWaitDelay', 0)
Opt('TrayMenuMode', 3)

Global Const $WM_TRAYNOTIFY = $WM_USER + 1
Global Const $NIN_BALLOONSHOW = $WM_USER + 2
Global Const $NIN_BALLOONHIDE = $WM_USER + 3
Global Const $NIN_BALLOONUSERCLICK = $WM_USER + 5
Global Const $NIN_BALLOONTIMEOUT = $WM_USER + 4
Global Const $subID = 1234
Global $iTip = 2
Global $psub = DllCallbackRegister("_subclass", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")
Global $hForm = GUICreate('')

DllCall("comctl32.dll", "bool", "SetWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID, "dword_ptr", 0)

GUIRegisterMsg($WM_TRAYNOTIFY, 'WM_TRAYNOTIFY')

Global $iShow = TrayCreateItem("Show New Tip")
TrayCreateItem("")
Global $iExit = TrayCreateItem("Exit")

TrayTip('Tip', 'This is a tray tip, click here.', 10, 1)

While 1
    Switch TrayGetMsg()
        Case $iShow
            TrayTip('Tip', 'This is a tray tip, click here. [ ' & $iTip & ' ]', 10, 1)
            $iTip += 1
        Case $iExit
            ExitLoop
    EndSwitch
WEnd

DllCall("comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID)
DllCallbackFree($psub)

Func WM_TRAYNOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Switch $hWnd
        Case $hForm
            Switch $lParam
                Case $NIN_BALLOONSHOW
                    ConsoleWrite('Balloon tip show.' & @CR)
                Case $NIN_BALLOONHIDE
                    ConsoleWrite('Balloon tip hide.' & @CR)
                Case $NIN_BALLOONUSERCLICK
                    ConsoleWrite('Balloon tip click.' & @CR)
                Case $NIN_BALLOONTIMEOUT
                    ConsoleWrite('Balloon tip close.' & @CR)
            EndSwitch
    EndSwitch
EndFunc   ;==>WM_TRAYNOTIFY

Func _subclass($hwnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData)
    #forceref $hwnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData
    Switch $uMsg
        Case $WM_TRAYNOTIFY
            Switch $uIdSubclass
                Case $subID
                    Switch $lParam
                        Case $NIN_BALLOONSHOW, $NIN_BALLOONHIDE, $NIN_BALLOONUSERCLICK, $NIN_BALLOONTIMEOUT
                            If $hForm Then
                                DllCall("user32.dll", "bool", "PostMessageW", "hwnd", $hForm, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
                            EndIf
                    EndSwitch
            EndSwitch
    EndSwitch
    Local $ret = DllCall("comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hwnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
    Return $ret[0]
EndFunc



Добавлено:
Сообщение автоматически объединено:

Удалось решить таким образом. Вызов функции SafeExit() вынес из функции OnAutoItExit() и поставил ее после основного цикла, а функцию OnAutoItExit() сделал таким образом:

Код:
While 1 ; ЦИКЛ
    If $UPDATE_ENABLE = 1 Then 
	   
    ElseIf $UPDATE_ENABLE = -3 Then
	    ExitLoop
    EndIf
    Sleep(500)
WEnd

SafeExit()

Func SafeExit()
    ConsoleWrite("exiting..." & @CRLF)
    DllCall("comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID)
    DllCallbackFree($psub)
EndFunc

Func OnAutoItExit()
    _WinAPI_PostMessage(_WinAPI_FindWindow('AutoIt v3 GUI', "HostProc"), $GET_MESSAGE, -3, 0)
    Delete()
    If $hDLL Then DllClose($hDLL)
	GUIDelete($hGUI)
	$UPDATE_ENABLE = -3 ; флаг завершения, который проверяется в цикле
EndFunc   ;==>OnAutoItExit


Может и криво это, но ошибки больше не стало
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
вот эти все вызовы и прочее это для обмена данными между процессами?
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
Для обмена сообщениями между процессами, только это:

Код:
_WinAPI_PostMessage(_WinAPI_FindWindow('AutoIt v3 GUI', "HostProc"), $GET_MESSAGE, -3, 0)


А пример, который я привел, это реализация событий сообщений в трее. Его я и использую в своем приложении.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Можно было сделать проще.
В том числе и обмен данными.
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
joiner сказал(а):
Можно было сделать проще.
В том числе и обмен данными.

Ну так покажи пожалста пример..)


Добавлено:
Сообщение автоматически объединено:

Но теперь появилась другая проблема. Если случается какое-то необработанное исключение, вылет, то процесс остается висеть мертвым. Это потому, что SafeExit в таких случаях остается не закрыт. Вот теперь я готов выслушать альтернативные способы от гуру...
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
для внеплановых выходов, когда скрипт сам завершает работу, то можно зарегистрировать функцию закрытия через
Код:
OnAutoItExitRegister('SafeExit')

насчет того, что скрипт может быть принудительно выгружен из процессов, то тут уж не знаю. такое бывает с разными программами. Их "недобитые" модули остаются висеть в процессах, когда происходит крах основной работы

в примере WM_TRAYNOTIFY обрабатывает твои нажатия
_subclass также реагирует на нажатия в трее и отсылает сообщения другим процессам. так?
можно использовать
Код:
_WinAPI_CreateFileMapping

для обмена данными
и отправлять данные о нажатиях сразу из WM_TRAYNOTIFY
тогда не нужно будет использовать функцию обратного вызова
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
Нет, нажатия не отсылаются другим процессам, они обрабатываются в текщем процессе, и это не относится к данной проблеме. Мне нужно закрыть субкласс, но чтобы винда на это действие не реагировала. В оригинальном примере (сообщения в трее) субкласс закрывается после основного цикла. То есть выход из цикла, а затем закрытие субкласса. Я попробовал такую реализацию, ошибки не стало, но вот, говорю же, что появилась теперь дргая проблема. А на OnAutoItExitRegister у меня уже зарегистрирована функция, как раз эта: OnAutoItExit()
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Зарегистрировать на выход можно несколько функций. А процесс остается висеть из-за функции обратного вызова.
Зачем нужна работа с субклассом в твоей реализации?
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
O!! :IL_AutoIt_1:
Фсё, заработало. Дело было не в бобине. Оказывается, на кнопку выхода я назначал вызов функции OnAutoItExit(), а надо было просто Exit, а зарегистрированная функция OnAutoItExit() отрабатывает вслед. Век учись))
Спасибо.


Добавлено:
Сообщение автоматически объединено:

joiner сказал(а):
Зачем нужна работа с субклассом в твоей реализации?

Я не знаю сам, взял рабочий пример и его использую. Знаю, что без субкласса события обрабатываться не будут. Я испробовал три или четыре разных примера, но все другие не работают на x64, этот единственный.
 
Верх