Что нового

Помогите перехватить завершение работы Windows

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
ynbIpb [?]
Ну я думаю это не для вандалов
Тогда достаточно вывести окно с предупреждением - просьбой не выключать компьютер, ИМХО, самый оптимальный вариант (для меня), так как все вышеуказанные действия, даже если и не делают что-то нехорошее, очень похожи на действия вируса и т.п.
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
Я сейчас как домой пришёл, пересмотрел ещё раз видео, глянул скрипт, глянул своё первое сообщение в этой теме. Что-то Вы тут напутали. Тут наоборот, если указанная строка найдена, то компьютер выключать можно, а если не найдена, то нельзя. А Вы сделали так, что если строка не найдена, то выключать можно, а если найдена, то нельзя. Вы сделали наоборот. Строка, которую мы ищем, это зашифрованная цифра 0. А 0 означает, что клиенты к моему компьютеру не подключены. Я попытался подправить код, запрет на разрешение, а разрешение на запрет, что-то не получилось.
Ещё я целый день над этим думал сегодня, решил, что надо дополнительно в папке со скриптом перед выключением компьютера создать txt-файл Command.txt со строкой OffServer, потом подождать, пока программа закроется. Программа созданный скриптом txt-файл сама откроет (для этого будет секундомер, чтобы программа каждую секунду проверяла файлы в папке со скриптом), прочитает в нём команду, выполнит нужные действия и сама закроется, а пока программа будет выполнять нужные действия (это, ИМХО, займёт меньше секунды), скрипт будет ждать, пока она закроется, а потом и сам завершит свою работу, и выключение компьютера продолжится.
 

Zaramot

I ♥ AutoIt
Сообщения
1,160
Репутация
660
ynbIpb, ваш скрипт у меня не работает. Что с ним, что без него. Я и перезагружаю и выключаю комп. и нечего не происходит.

P.S. У меня Windows XP SP3 :smile:
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
Zaramot, наверное madmasles правильно говорил, надо блокировать реестр и диспетчер задач. Попробуйте так сделать.
 

Zaramot

I ♥ AutoIt
Сообщения
1,160
Репутация
660
Zaramot, наверное madmasles правильно говорил, надо блокировать реестр и диспетчер задач. Попробуйте так сделать.

А зачем ?! я не вандал :smile:

P.S. При выключение компа я не пытался использовать реестр и диспетчер задач. Тем более что я уверен на 99,9% что дело не в них. ;)
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
Ну вот вроде бы получилось у меня исправить функцию обработки сообщение. У меня правда функция длиннее получилась. Есть ли тут ошибки?

Код:
Func _Shutdown ($hWndGUI, $MsgID)
    If FileExists ($sTmpFile) = 0 Then ; если файл не существует, то
        Return 1 ; возвращаем 1, тоесть разрешаем завершение работы
    EndIf
    $hTmpFile = FileOpen ($sTmpFile, 0); открываем файл для чтения
    $sTmpFileData = FileRead ($hTmpFile) ; читаем файл целиком
    FileClose ($hTmpFile); закрываем файл
    $iPos = StringInStr ($sTmpFileData, "f5kuDrmNRqJO0oTOMVUjhw=="); проверяем наличие строчки в тексте
    If $iPos = 0 Then ; если строка не найдена, то выключать нельзя
        Return 0 ; возвращаем 0
        $iMsgFlg = 1 ; выставляем флаг месаджбокса 1, значит показать его
		RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableTaskMgr', 'REG_DWORD', '0')
		RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableRegistryTools', 'REG_DWORD', '0')
    EndIf
	; Далее я тут хочу создать файл Command.txt, где будет текст OffServer.
	; Пробуем. Правда, я тут не совсем уверен, что здесь нет ошибок. Наверняка, их тут много. Я читал в русской справке, что при открытии файла для записи если его нет, то он будет автоматически создан.
	$file = FileOpen("Command.txt", 1)
	FileWriteLine($file, "OffServer")
	FileClose($file)
	; Ждём, пока моя программа завершит свою работу.
	ProcessWaitClose("Start.exe")
	; Теперь перед выходом разблокируем диспетчер задач и реестр.
	RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableTaskMgr', 'REG_DWORD', '0')
    RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableRegistryTools', 'REG_DWORD', '0')
    Return 1 ; возвращаем один, значит выключать можно
EndFunc


Ну как, ynbIpb правильно?
А так в общем вот ещё одна моя версия скрипта, но уже полная, не только вышеуказанная функция. Я сюда свои комментарии добавил, их советую прочитать.

Код:
#NoTrayIcon ; не показывать иконку в трее
;защита от запуска двух копий 
If WinExists("Zxh3vfjklfjk4lgf4kgf") Then Exit 
AutoItWinSetTitle("Zxh3vfjklfjk4lgf4kgf")
; проверка версии ОС
If @OSVersion <> "WIN_XP" Then ; если не XP, то сообщаем и выходим
    MsgBox (16, "Ошибка!", "Это приложение работает только на Windows XP")
    Exit
EndIf

; Блокируем диспетчер задач и реестр, как сказал тут один человек.
RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableTaskMgr', 'REG_DWORD', '1')
RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableRegistryTools', 'REG_DWORD', '1')

$sTmpFile = @TempDir & "\MkXXov0P31CQq1o6SBsdw==.tmp" ; путь к файлу, который отслеживаем
$sMsgTxt = "Выключать компьютер в данный момент нельзя, так как к нему ещё подключены пользователи." & @CRLF _ 
& "Подождите, пока они закончат свою работу, или сообщите им, что Вы отключаетесь, потом повторите попытку."
$WM_QUERYENDSESSION = 0x0011 ; сообщение Windows о завершении работы
$FIRST_SHUTDOWN_RANGE = 0x03FF ; значение, наивысший приоритет на получение сообщения о завершении работы
$iMsgFlg = 0 ;флаг, который определяет показывать месаджбок или нет

$hGui = GUICreate ("shutdown_stop"); создаём гуй, который будет ловить сообщение
GUISetState (@SW_HIDE, $hGui); скрываем его, ибо он нам не нужен

GUIRegisterMsg ($WM_QUERYENDSESSION, "_Shutdown"); ожидаем сообщения от системы, и выполняем указанную функцию
_WinAPI_SetProcessShutdownParameters($FIRST_SHUTDOWN_RANGE); устанавливаем приоритет

While 1 ; бесконечный цикл, в ожидании сообщения.
    Sleep(100); пауза, чтобы не грузить процесс
    If $iMsgFlg = 1 Then _msgbox() ; если флаг стал равен 1, запускаем функцию отображения месаджа
WEnd

; наша функция, обрабатывающая сообщение
Func _Shutdown ($hWndGUI, $MsgID)
    If FileExists ($sTmpFile) = 0 Then ; если файл не существует, то
        Return 1 ; возвращаем 1, тоесть разрешаем завершение работы
    EndIf
    $hTmpFile = FileOpen ($sTmpFile, 0); открываем файл для чтения
    $sTmpFileData = FileRead ($hTmpFile) ; читаем файл целиком
    FileClose ($hTmpFile); закрываем файл
    $iPos = StringInStr ($sTmpFileData, "f5kuDrmNRqJO0oTOMVUjhw=="); проверяем наличие строчки в тексте
    If $iPos = 0 Then ; если строка не найдена, то выключать нельзя
        Return 0 ; возвращаем 0
        $iMsgFlg = 1 ; выставляем флаг месаджбокса 1, значит показать его
		RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableTaskMgr', 'REG_DWORD', '0')
		RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableRegistryTools', 'REG_DWORD', '0')
    EndIf
	; Далее я тут хочу создать файл Command.txt, где будет текст OffServer.
	; Пробуем. Правда, я тут не совсем уверен, что здесь нет ошибок. Наверняка, их тут много. Я читал в русской справке, что при открытии файла для записи если его нет, то он будет автоматически создан.
	$file = FileOpen("Command.txt", 1)
	FileWriteLine($file, "OffServer")
	FileClose($file)
	; Ждём, пока моя программа завершит свою работу.
	ProcessWaitClose("Start.exe")
	; Теперь перед выходом разблокируем диспетчер задач и реестр.
	RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableTaskMgr', 'REG_DWORD', '0')
    RegWrite('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System', 'DisableRegistryTools', 'REG_DWORD', '0')
    Return 1 ; возвращаем один, значит выключать можно
EndFunc
; Может ещё что-то тут подправить?

; наша функция, отображающая месаджбокс
Func _msgbox()
    MsgBox (48, "Сообщение от IntServer", $sMsgTxt)
    $iMsgFlg = 0 ; после показа месаджа, выставляем флаг опять в ноль
EndFunc

; функция из библиотеки WinAPIEx_3.3 от Yashied
Func _WinAPI_SetProcessShutdownParameters($iLevel, $fDialog = 0)

    Local $Ret = DllCall('kernel32.dll', 'int', 'SetProcessShutdownParameters', 'dword', $iLevel, 'dword', Not $fDialog)

    If (@error) Or (Not $Ret[0]) Then
        Return SetError(1, 0, 0)
    EndIf
    Return 1
EndFunc   ;==>_WinAPI_SetProcessShutdownParameters


Ну что, нет ли тут ошибок?

Zaramot сказал(а):
А зачем ?! я не вандал :smile:
Ну и что? Ну раз у Вас скрипт не работает, то как тогда быть? ynbIpb, может это не только от ОС зависит, но и от сервис-пака? Может SP3 не подойдёт? У меня SP2. :smile:
Zaramot сказал(а):
P.S. При выключение компа я не пытался использовать реестр и диспетчер задач. Тем более что я уверен на 99,9% что дело не в них.
Zaramot, надеюсь, ynbIpb нам обоим в этом деле поможет.
 

Zaramot

I ♥ AutoIt
Сообщения
1,160
Репутация
660
Может у меня выдаёт ошибку потому-то @TempDir у меня не C:\WINDOWS\Temp, a C:\Document and Settings\Admin\Local Settings\Temp :scratch:
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
Вот как-раз в C:\Document and Settings\Admin\Local Settings\Temp и производится действие. Попробуйте закинуть файл с моей зашифрованной строкой туда.
 

ynbIpb

Скриптер
Сообщения
399
Репутация
110
ну я проводил опыты на SP3, как видно из видео - завершение работы прекращается.
Где бы не была Ваша папка Temp, скрипт получает к ней путь от винды благодаря использованию макроса @TempDir. Видимо файл не туда положили.
И блокировка реестра и диспетчера здесь не играет никакой роли. Это нужно только для того, чтобы юзер не попытался принудительно выключить систему другими путями.

по поводу ожидания ProcessWaitClose("Start.exe")
Этого делать не рекомендуется, так как система долго ждать не будет, нужно срочно ей вернуть ответ.

А по поводу изменения условия, достаточно поменять тут: If $iPos = 0 Then, вот так: If $iPos <> 0 Then
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
ynbIpb сказал(а):
по поводу ожидания ProcessWaitClose("Start.exe")
Этого делать не рекомендуется, так как система долго ждать не будет, нужно срочно ей вернуть ответ.
И что же получается, Windows даже одной секунды не может подождать? Ну программа Start.exe ежесекундно будет проверять файлы в папке скрипта, и где будет скрипт, там будет и файл Start.exe. Как только программа Start.exe обнаружит файл Command.txt, она тут же проверит его, а потом перейдёт по заданной ссылке в интернете на php-скрипт, который записывает состояние компьютера, php-скрипт запомнит, что компьютер выключен, записав это в специальный txt-файл. Ну а потом программа Start.exe закроется. Вот это всё будет одну секунду всего идти! И что же получается, Windows одну секунду подождать не может? А отложить на несколько секунд завершение работы никак нельзя?
ynbIpb сказал(а):
А по поводу изменения условия, достаточно поменять тут: If $iPos = 0 Then, вот так: If $iPos <> 0 Then
Это понятно. А после Return 0 на 1 и 1 на 0 надо было заменять? Как Вы видели, я заменял, правильно сделал?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Только для Windows XP с любым SP или без него.

После того, как система вызвала WM_QUERYENDSESSION, у вас есть 5 сек., чтобы дать ответ (0 - отменить выключение; 1 - продолжить). Если вы ответили 1, то можете еще обработать WM_ENDSESSION. Если по истечении этого времени вы не ответили на сообщение, то появится диалоговое окно с прогрессом на завершение программы. В этом случае отводится ~20 сек для принудительного закрытия (задается где-то в реестре).

Если программа Start.exe использует соединение с интернетом, то я крайне не рекомендую вызвать ProcessWaitClose("Start.exe") в обработчике WM_QUERYENDSESSION. Придумайте что-нибудь получше...
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
А почему не рекомендуете?
Когда я пробовал когда-то выключать компьютер, и у меня выключение тормозило, интернет не отключался, а просто закрывались программы по порядку. Когда закроются программы, тогда и интернет отключится. Как-раз я и перехватываю завершение работы системы именно потому, что делаю серверную программу, использующую соединение с интернетом. Если клиенты к серверу подключены, компьютер не выключается, если нет - открывается php-скрипт, который потом передаст другим клиентам, не подключившимся ранее, что мой компьютер выключен, потом компьютер выключается.
А Вы что думаете, что интернет сразу отключится, а потом только Windows будет передавать всем окнам сообщение о завершении? Сомневаюсь...
Yashied сказал(а):
Придумайте что-нибудь получше...
То есть, Вы мне предлагаете какую-нибудь другую программу придумать, не использующую соединение с интернетом? Или как-нибудь по-другому код записать? Если Вы мне предлагаете по-другому написать код, то как это сделать? Какой код писать? Если Вы мне предлагаете придумать программу, не использующую соединение с интернетом - я на это не соглашусь, так как в данный момент мне нужна именно такая программа...
Иначе никак не сделать!
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Если программа соединяется с интернетом, то нельзя заранее сказать сколько времени ей на это потребуется (сервер может ведь и не отвечать).
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
Ну тогда поставлю там таймаут на 5 секунд. Если в течение этого времени сервер не ответит - программа закроется принудительно.
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
У меня сейчас такая мысль появилась: а Windows может наверное послать сообщение о завершении работы прежде программе Start.exe, а потом скрипту! Но тогда моя программа завершит работу быстрее, чем скрипт! Как тогда быть?
 
Автор
И

Игорь В

Новичок
Сообщения
20
Репутация
0
Ну что, все разбежались с форума что ли? Ответа не вижу...
 
Верх