Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Прога не дает завершиться винде. Как побороть?


Автор: tippmann 29.3.2004, 21:39
Программка с использованием RxTrayIcon. Написана на Дельфи 6. Почти всегда свернута в трей.
Полезная работа: отдельным потоком коннектится по UDP к серверу и периодически опрашивает состояние, которое отображает в StringGrid.
Проблема:
При завершении работы или перезагрузке в трее остается только иконка этой проги (она продолжает работать), и винда не может завершиться.
Причем, если окно проги активно - сама прога завершается, а винда перегружается только при повторном тычке на кнопку "Перезагрузка". Если окно проги свернуто в трей (т.е. видно только иконку) - совсем ничего не происходит (и прога работает, и винда не завершается).
Где чего написать чтоб винда нормально завершилась - я уж и не знаю. Все перепробовал, все ФАКи перерыл...
Вот все процедуры которые вроде отношение имеют к этому:
Код

procedure TForm1.WMQueryEndSession
           (Var Message: TWMQueryEndSession);
begin
inherited;
 CleanUp;
 Message.Result:= integer(true);
 //postquitmessage(0);

end;

//****************************************************
procedure TForm1.CleanUp;
begin
with TRegistry.Create do
 begin
 try
   RootKey := HKEY_CURRENT_USER;
   if OpenKey('\Software\keysoft', True) then
     begin
     WriteInteger('left', Form1.Left);
     WriteInteger('top', Form1.Top);
     end;
 finally
   CloseKey;
   Free;
 end;
 end;
 Application.Restore;
 Application.BringToFront;
 AppClosing := true;
 MainThread.ExitThread(nil); //оборвали нить
 application.terminate;
end;
//****************************************************
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
 cleanup;
 CanClose := true;

end;

Автор: <Spawn> 30.3.2004, 04:52
То есть это не твоя программа? Тогда сделай свою и при зафершении работы виды делай FindWindow + TerminateProcess

Автор: tippmann 30.3.2004, 11:09
<Spawn> - это моя программка. Просто я первый раз столкнулся с необходимостью завершить нормально прогу при перезагрузке винды. Вот собственно по этому за советом и пришел.
Еще раз вопрос, может даже поконкретней:
Если окно проги развернуто, при попытке перегрузиться прога завершается, а винда нет. Винда нормально завершится при повторном тычке на кнопке Перезагрузка. ИМХО моя программка перед самым завершением своей работы должна уведомить винду сообщением, что она типа закончила работу и можно перезагружаться. Что это за сообщение и когда (куда, кому) его лучше послать?

Автор: RA 30.3.2004, 12:37
А что за Процедура - cleanup ?

Автор: Maverick 30.3.2004, 14:04
Цитата
А что за Процедура - cleanup ?


Вероятно пользовательская... По аналогии с FoxPro названо - при закрытии окна, там такая штука есть...

Автор: p0s0l 30.3.2004, 15:52
RAdmin, Maverick, да вы что ? CleanUp же расписана в коде !

tippmann, попробуй сделать в конце CleanUp TerminateProcess(GetCurrentProcess); вместо Application.Terminate



Автор: tippmann 31.3.2004, 15:13
p0s0l
Спасибо. При чтении доки по TerminateProcess обнаружил что и Thread я не правильно завершал. НО проблему это НЕ решило...
Если окно проги активно - все ОК, срабатывает процедура FormCloseQuery и винда вместе с прогой завершаются.
Если прога свернута - ничего не происходит. Все остальные проги завершаются кроме моей...
Отсюда я делаю вывод, что проблема заключается в следующем: окно проги прячется функцией ShowWindow(Application.Handle, SW_HIDE); (бо я не хочу чтоб она висела в таскбаре). Т.е. остается только иконка в трее. Если не прятать таким образом окно, а просто сворачивать - все нормально.

Куда в таком случае Винда посылает сообщение на закрытие и как поймать это сообщение?

ЗЫ: Ведь полно таких прог, у которых только иконка в трее, и все у всех работает. Неужели никто не писал такое никогда?
Прога без исходников лежит тут http://baton.itkm.ru/progs.php ~720 Kb Исходники для D6 могу выслать почтой если кого заинтересует.

Автор: RA 31.3.2004, 17:04
А что нельзя просто Form1.visible:=false; ?

Автор: tippmann 31.3.2004, 21:29
Цитата
А что нельзя просто Form1.visible:=false; ?

Нельзя. Я ж ясно написал - не хочу чтоб прога была видна в таскбаре. Хочу чтоб только иконка была в трее.

Автор: z-END 31.3.2004, 22:35
tippmann
попробуй вместо application.terminate делать ExitProccess(0);
у меня была похожая проблемма при работе с плагинами так вот ExitProccess очень помог.

Автор: RA 31.3.2004, 22:50
tippmann э не внимательно тебя прочёл. Слух а программа под 9x чтоли ?

Автор: tippmann 31.3.2004, 22:58
RAdmin
Я ее пишу сидя в win 2000, а уж куда ее люди ставить будут - не мое дело...
По идее везде работать должно... Я там ничего такого специфичкого не использовал.
И с чего можно было взять что она под 9х?

Автор: RA 31.3.2004, 23:18
tippmann да ты про таскбар сказал вот я и подумал что под 9x biggrin.gif

Автор: tippmann 31.3.2004, 23:35
RAdmin
мдя, всех бывает подглючивает...

nJIaKca.spb
Спасибо!!! ExitProccess(0); и мне помог. Как раз то что нужно было...
Эх, поставил бы тебе плюсик, да мне пока не разрешають smile.gif

Для тех кто будет после меня колупаться:
при применении ExitProccess(0); даже если форма скрыта функцией ShowWindow(Application.Handle, SW_HIDE); и отсутствует в списке выполняемых приложений, происходит вызов процедуры FormCloseQuery, где можно сделать завершающие действия, и винда завершится нормально.

При использовании TerminateProcess(GetCurrentProcess,0); или application.terminate; этого не происходит. Винда нормально завершиться не может (если окно скрыто).

Да и ваабще как я понял использовать ExitProccess(0); предпочтительнее всего, бо он там сам еще кучу полезной работы делает типа отсоединения DLL и завершения Thread...


Автор: p0s0l 1.4.2004, 00:29
tippmann, поставлю плюсик nJIaKca.spb, раз тебе не позволено, а человек заслужил.

Автор: tippmann 2.4.2004, 12:38
Гы. Я всех обманул...
Прога один раз закрылась в свернутом виде, и я подумал что все ОК (или меня проглючило).
Вот щас опять долбаю... Все таки - хто получает сообщение на закрытие проги, если у проги форма спрятана? И как отловить его, сообщение это?
Вот чего щас есть:
Код
//****************************************************
procedure TForm1.WMQueryEndSession
           (Var Message: TWMQueryEndSession);
begin
inherited;
 showmessage('WMQueryEndSession'); //вот это сообщение ни разу не видел
 Message.Result:= integer(true);
 CleanUp;
end;
//****************************************************
procedure TForm1.CleanUp;
begin
 Application.Restore;
 Application.BringToFront;
 //ShowWindow(Application.Handle, SW_NORMAL);
 RxTrayIcon1.Free;
 AppClosing := true;
 PostQuitMessage(0);
 ExitProcess(0);
end;
//****************************************************
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
 showmessage('FormCloseQuery'); //выскакивает когда форма видна
 CanClose := true;
 cleanup;
end;

Т.е. процедура CleanUp (в которой выход и сделан) не выполняется, бо ее запустить неоткуда.
Процедура TForm1.WMQueryEndSession ваабще ни разу не выполнилась... Толи сообщение это не приходит, толи приходит не туда...

Автор: dm9 2.4.2004, 18:31
Может, попробовать использовать finalization??

Код
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;

type
 TForm1 = class(TForm)
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

var
  f : text;

{$R *.dfm}

initialization

finalization

  AssignFile (f, 'd:\111.txt');
  ReWrite (f);
  CloseFile (f);

end.

Добавлено @ 18:33
Нет, ну можно, конечно, поизвращаться.. smile.gif
Код
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;

type
 TForm1 = class(TForm)
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

procedure d; far;
var
  f : text;
begin
  AssignFile (f, 'd:\test1.txt');
  ReWrite (f);
  CloseFile (f);
end;

{$R *.dfm}

initialization

  ExitProc := @d;

end.


Но это бред...

Автор: dm9 2.4.2004, 18:52
Хм, прошу прощения.
Это дело не работает. Также не работает и AddTerminateProc,
если сначала вызвать
ShowWindow(Application.Handle, SW_HIDE); и
Form1.Hide;

Странно... Мне тоже уже стало интересно smile.gif

Автор: tippmann 2.4.2004, 19:07
Вот и я про что...
Но проги то работают тем не менее, от сторонних производителей smile.gif
Написать чтоль письмецо в фирму сделавшую регет biggrin.gif

Автор: dm9 2.4.2004, 19:17
О! Эксперименты показали, что от Ctrl+Alt+Del не спастись, если прога без видимой формы и скрыта из таскбара. Но при перезагрузке (по крайней мере, при лог-оффе, перегружаться не хочу) срабатывает AddTerminateProc. Вот прога для эксперимертов.

Код
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

var
  f : text;

procedure d; far;
begin
  AssignFile (f, 'd:\testtesttesttesttesttesttesttesttesttest1.txt');
  ReWrite (f);
  CloseFile (f);
end;

function gh : Boolean;
begin
  AssignFile (f, 'd:\testtesttesttesttesttesttesttesttesttest3.txt');
  ReWrite (f);
  CloseFile (f);
  Result := true;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
//  ShowMessage ('!');
//  canclose := true;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowWindow(Application.Handle, SW_HIDE);
  Hide;
end;

initialization

  ExitProc := @d;
  AddTerminateProc (gh);

finalization

  AssignFile (f, 'd:\testtesttesttesttesttesttesttesttesttest2.txt');
  ReWrite (f);
  CloseFile (f);

end.


smile.gif

Автор: pascal 3.4.2004, 02:45
чё, всё ещё не решили задачу?

если нет, кинте мне исходничек на мыло MJ собака NE KTO.RU (пробелы удалить, собаку заменить)

Автор: tippmann 4.4.2004, 10:04
Сдается мне что я понял в чем беда - я прогу сворачивал...
А внимательно присмотевшись ко всем остальным понял, что они прячутся, а не сворачиваются (т.е. форма висит, но ее не видно).
Попробовать немного некогда...
О результате обязатеньно отпишу.

Автор: PILOT 4.4.2004, 11:34
Кстати, я иногда вот так вот делаю...

Код

procedure Shut_Down_PC;
var
 hToken: THandle;
 Luid: TLargeInteger;
 tkp: TTokenPrivileges;
 ReturnLength: Cardinal;
begin
if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES,hToken) then
begin
    LookUpPrivilegeValue(nil,'SeShutdownPrivilege',Luid);
    tkp.Privileges[0].Luid:=Luid;
    tkp.PrivilegeCount:=1;
    tkp.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED;
    if AdjustTokenPrivileges(hToken,False,tkp,0,nil,ReturnLength) then
    begin
       if not ExitWindowsEx(EWX_FORCE or EWX_POWEROFF,0) then
       begin
          ShowMessage('Компьютер не будет перезагружен'+#13+#10+
          'из-за отсутствия прав!');
       end;
    end;
end;
end;


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

СУВ.

Автор: pascal 5.4.2004, 02:29
Цитата
Сдается мне что я понял в чем беда - я прогу сворачивал...

Не думаю что в этом дело...

Некоторые персоны переписывая обработчик зыбывают его завершить

пример:
Код
procedure TTrayIcon.WndProc(var Message: TMessage);
begin
 if Message.Msg=WM_TRAYICON then
   ...
 else if Message.Msg=WM_TIMER then
   ...
 else if Message.Msg=WM_ACTIVATEAPP then
 begin
   ...
 end
 else with Message do Result := DefWindowProc(FHandle, Msg, WParam, LParam);
end;

Вот некоторые забывают о последней строчке...
Казалось бы и без неё всё отлично работает, но будут подобные глюки...

Автор: tippmann 6.4.2004, 17:57
Не народ, я был прав.
Перестал минимизировать форму - все стало работать как надо.
Просто стал перехватывать сообщение о минимизации SC_MINIMIZE и вместо минимизации делать Application.MainForm.Hide

PILOTIK
Ну это уж совсем радикальный способ smile.gif

В общем тему можно считать закрытой.

ЗЫ: вот http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&threadm=997822550%40p16.f603.n5020.z2.FidoNet.ftn&rnum=1&prev=/groups%3Fq%3Drxtrayicon%2Bwindows%2Bshutdown%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3D997822550%2540p16.f603.n5020.z2.FidoNet.ftn%26rnu%20m%3D1 еще про кое что написано, но мне не помогло... Видать не догнал я толком чего сделать надо...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)