Форум: "Система";
Текущий архив: 2004.05.02;
Скачать: [xml.tar.bz2];
ВнизКак закрыть программу, когда пользователь хочет перезагрузиться? Найти похожие ветки
← →
Status (2004-03-04 00:28) [0]Моя программа запускается при загрузке операционной системы и невидима для пользователя.
Мне нужно ловить момент, когда пользователь хочет перезагрузиться или завершить работу windows, чтобы закрыть программу, иначе перезагрузки не происходит.
Ловлю сообщение WM_QUERYENDSESSION:
procedure WMQueryEndSession(var Message: TWMQueryEndSession); message WM_QUERYENDSESSION;
далее в коде
PROCEDURE TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
var a:TCloseAction;
BEGIN
FormClose(Form1, a);
Message.Result := 1;
form1.destroy;
END;
В файле проекта есть следующая строчка:
Application.ShowMainForm:=false;
Так вот, когда пытаюсь перезагрузиться то перезагрузки не происходит, но когда убираю из файла проекта эту строчку, то нормально windows перезагружается. Не пойму в чём дело.
← →
Defunct © (2004-03-04 01:10) [1]Делайте на уровне приложения а не главной формы:
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
protected
Procedure IdleMessage(var MSG:tagMSG;var Handled:Boolean);
End;
var
Form1: TForm1;
implementation
{$R *.dfm}
Procedure TForm1.IdleMessage;
Begin
With MSG.message=WM_QUERYENDSESSION Then
Begin
Handled := True;
Destroy;
Application.OnMessage := Nil;
Application.Terminate;
End;
End;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := IdleMessage;
End;
← →
Defunct © (2004-03-04 01:24) [2]ЗЫ, я думаю будет лучше проверять не WM_QUERYENDSESSION, а WM_ENDSESSION. ибо будет немного глупо выглядеть, когда ваша программа-агент завершится, а какая-то другая программа приостановит перезагрузку.
← →
Defunct © (2004-03-04 01:54) [3]Опечатка..
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
protected
Procedure IdleMessage(var MSG:tagMSG;var Handled:Boolean);
End;
var
Form1: TForm1;
implementation
{$R *.dfm}
Procedure TForm1.IdleMessage;
Begin
If MSG.message=WM_ENDSESSION Then
Begin
Handled := True;
Destroy;
Application.OnMessage := Nil;
Application.Terminate;
End;
End;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := IdleMessage;
End;
Код проверен, работает исправно с
Application.ShowMainForm := False;
← →
Alexander666 © (2004-03-04 03:59) [4]
> Defunct © (04.03.04 01:10) [1]
> Делайте на уровне приложения а не главной формы:
ИМХО, как-то странно звучит.
← →
Defunct © (2004-03-04 04:32) [5]> ИМХО, как-то странно звучит.
В контексте сабжа это было про отлов сообщения WM_ENDSESSION и завершение работы посредством Close главной формы. Отлов сообщение WM_ENDSESSION и Application.Terminate это уже на уровне процесса. Не знаю как обрабатывается выход и отлов при Application.ShowMainForm = False, но на практике заметил, что с этим параметров сообщение окном формы не отлавливается, более того Close не срабатывает должным образом.
← →
y-soft © (2004-03-04 07:55) [6]Вообще-то нормально написанное приложение прекрасно завершается системой и без ловли WM_ENDSESSION и WM_QUERYENDSESSION
Чаще эти обработчики используются как раз для того, чтобы запретить Shutdown
Лишь иногда, когда необходимо корректно завершить длительный процесс или обеспечить завершение группы процессов в определенном порядке, в обработчике сначала приостанавливают перезагрузку, заканчивают долгую операцию, а потом приложение само повторно инициализирует Shutdown. Но способ этот достаточно капризный и не всегда приводит к ожидаемым результатам (например: Shutdown вызван ПО источника бесперебойного питания. В этом случае приостановка перезагрузки может привести к порче ОС и другим неприятностям, т.к. компьютер может вырубится просто из-за падения питающего напряжения)
← →
Status (2004-03-04 19:20) [7]To Defunct:
Что то по-моему ваш код вообще не работает, то есть сообщение не отлавливается.
Если допустим я хочу чтобы когда пользователь хочет перезагрузиться, чтоб перезагрузки не было и чтобы моя прога не закрылась я должен написать:
If MSG.message=WM_ENDSESSION Then
Begin
Handled := false;
End;
Но никакой реакции - происходит перезагрузка.
И если вставляю какой нибудь код между
If MSG.message=WM_ENDSESSION Then
Begin
*********
End;
То он тоже не выполняется.
← →
Defunct © (2004-03-05 00:52) [8]Специфика платформы..
В таком случае просто попробуйте в вашей, изначально приведенной процедуре, выполнить этот кусок кода:Procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
Begin
Case Application.MessageBox("Закрыть программу?","exiting",MB_YESNO) Of
IDYES:
Begin
Message.Result := 1;
Destroy;
Application.Terminate;
End;
IDNO: Message.Result := 0;
End;
End;
У меня работает.
Кстати, по поводу вашего второго вопроса
чтоб перезагрузки не было и чтобы моя прога не закрылась я должен написать:
If MSG.message=WM_ENDSESSION Then
Begin
Handled := false;
End;
"Handled" не имеет никагого отношения к Result сообщения, устанавливая в True, вы тем самым даете понять что сообщение обработано.
PS: из сабжевого вопроса, я так понял Вам было нужно чтобы программа завершалась, а не приостанавливала завершение сессии.
← →
Defunct © (2004-03-05 01:03) [9]ЗЫ, а вообще y-soft © (04.03.04 07:55) [6] прав.
← →
Status (2004-03-06 03:05) [10]Понял в чём проблема!
В общем надо было мне, чтобы происходила нормальная перезагрузка компа, когда моя прога запущена. Но как оказалось, перезагрузка приостанавливается. Сообщение WM_ENDSESSION не ловится. А если убираю строчку Application.ShowMainForm:=false;
то всё нормально.
Самое интересное, что когда создаю новое чистое приложение, вставляю эту строчку и делаю обработку сообщения WM_ENDSESSION, то всё без проблем.
Так вот, как оказалось, проблема в компоненте TNMSmtp!!! (который я использую в своей программе).
Стоит убрать его и сообщение WM_ENDSESSION ловится отлично.
Вот так то.
По этому поводу вопрос: каким образом решить эту проблему. Я вижу я пути:
1). Создавать NMSmtp в процессе работы программы и после отсылки почты удалять и так каждый раз. Но может возникнуть ситуация, что пользователь хочет перезагрузиться, а NMSmtp существует, тогда облом.
2). Отсылать почту каким-ниубдь другим методом, только каким? Я не знаю.
3). Отлавливать сообщение WM_ENDSESSION каким-либо другим методом, ставить глобальный хук. Как это сделать?
← →
Alexander666 © (2004-03-06 06:20) [11]Агааа!!! Трояна пишем или червя?! :-)) Отсылай почту методами API, в Интернете в факах поройся... или, если уж это действительно, что компонент мешает перезагружаться (хотя я в этом сомневаюсь), то переделывай сам этот компонент. Ищи причину его упорства при перезагрузке в исходных кодах.
← →
Status (2004-03-06 14:14) [12]Всё таки интересует вопрос, как можно поставить хук на WM_ENDSESSION
← →
Status (2004-03-06 15:07) [13]Попробовал поставить хук на WH_GETMESSAGE:
GlobalData^.HookHandle_Getm:=SetWindowsHookEx(WH_GETMESSAGE, @GetmHook, HInstance, 0);
Function GetmHook(Code: Integer; ParamW: WPARAM; ParamL: LPARAM): LRESULT;stdcall;
Begin
If Code<0 Then
Begin
Result := CallNextHookEx(GlobalData^.HookHandle_Getm, Code, ParamW, ParamL);
Exit;
End;
if (Code=HC_ACTION) then
begin
with TMsg(Pointer(paraml)^) do
if (message = WM_ENDSESSION) then
begin
SendMessage(GlobalData^.ProgHandle_Getm, WM_TESTMES, paramw, Code);
end;
end;
Result := CallNextHookEx(GlobalData^.HookHandle_getm, Code, ParamW, ParamL);
End;
Не работает, но если делаю проверку message = WM_KEYDOWN то работает.
Может с помощью хука на WH_GETMESSAGE нельзя отловить сообщение о перезагрузке системы?
Страницы: 1 вся ветка
Форум: "Система";
Текущий архив: 2004.05.02;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.035 c