Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

Некорректное завершение работы


AndreyRus ©   (15.09.23 08:53

Если при открытом модальном окне приложению послать WM_CLOSE, приложение "падает". Ошибка возникает в KOL.PAS на строке Applet.DF.fModalForm := nil; функции TControl.ShowModal

Попытался предотвратить возникновение ошибки в обработчике закрытия главной формы, но это не помогло.


procedure TMainForm.MainFormClose(Sender: PObj; var Accept: Boolean);
begin
 if ModalForm <> nil then ModalForm.Form.Free;
end;


Есть еще идеи как предотвратить эту ошибку?


Vladimir Kladov ©   (15.09.23 14:45[1]

Извне посылает? Другое приложение? Или ваш код изнутри своего приложения?

Вообще, судя по коду в этом месте, скорее всего, уже Aplet=nil. Можно попробовать напрямую добавить в код KOL.pas проверку
if Applet <> nil then Applet.DF.fModalForm := nil;

но не факт, что не вылезет что-то еще дальше. Может, лучше по щам надавать тому, кто через winapi окнам напрямую сообщения рассылает?


RusSun ©   (17.09.23 06:35[2]

Доброе время суток.
to AndreyRus:
Можете скинуть небольшой пример демонстрирующий ошибку. (Можно через яндекс диск или как Вам удобно или на почту)

Просто почта указанная на форуме ранее не работает. (даёт отбойник No such user!)


AndreyRus ©   (17.09.23 21:58[3]


> Извне посылает? Другое приложение? Или ваш код изнутри своего
> приложения?


Оба варианта.

1. В моей программе есть значок в SysTray в контекстном меню которого есть пункт "Выход"


procedure TMainForm.TrayPopupMenuExit(Sender: PMenu; Item: Integer);
begin
 Form.Close;
end;


Вызов этой процедуры при открытом модальном окне приводит к ранее описанному сбою. Вероятно это можно исправить, если в процедуре TMainForm.TrayPopupMenuExit перед вызовом Form.Close проверить все имеющиеся в программе модальные окна на предмет их использования и принудительно их закрыть. Но вот, что делать со вторым вариантом проявления этой ошибки я пока даже предположить не могу.

2. Моей программе требуется возможность ее корректно завершения другой программой. Я реализовал это через именованный блок виртуальной разделяемой памяти, куда стартующая программа записывает хендл окна апплета:


procedure StartNormal;
var
 MapView: Pointer;
begin
 UniqueMapping:= CreateFileMapping($ffffffff, nil, PAGE_READWRITE, 0, SizeOf(THandle), PChar(ProjectName));
 MapView:= MapViewOfFile(UniqueMapping, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(THandle));
 THandle(MapView^):= Applet.GetWindowHandle;
 UnmapViewOfFile(MapView);
end;


Вторая программа считывает и использует этот хендл:


function StopAlreadyRunningProgram: boolean;
var
 MapView: Pointer;
 ProcessHandle: THandle;
 UniqueMapping: THandle;
begin
 Result:= True;
 UniqueMapping:= OpenFileMapping(FILE_MAP_READ, True, PChar(ShortProjectName));
 if UniqueMapping <> 0 then
 begin
   MapView:= MapViewOfFile(UniqueMapping, FILE_MAP_READ, 0, 0, SizeOf(THandle));
   GetWindowThreadProcessId(HWND(MapView^), ProcessHandle);
   ProcessHandle:= OpenProcess(PROCESS_ALL_ACCESS, True, ProcessHandle);
   PostMessage(HWND(MapView^), WM_CLOSE, 0, 0);
   if WaitForSingleObject(ProcessHandle, 3000) = WAIT_TIMEOUT then Result:= False;
   UnmapViewOfFile(MapView);
   CloseHandle(UniqueMapping);
 end;
end;


При открытом модальном окне в первой программе возникает та же самая ошибка.


> Вообще, судя по коду в этом месте, скорее всего, уже Aplet=nil.
>  Можно попробовать напрямую добавить в код KOL.pas проверку
> if Applet <> nil then Applet.DF.fModalForm := nil;
> но не факт, что не вылезет что-то еще дальше.


Не помогло. Где то дальше опять возникает исключение.


AndreyRus ©   (17.09.23 22:11[4]


> Можете скинуть небольшой пример демонстрирующий ошибку.

Предполагаю, что смоделировать эту ошибку можно, бросив на модальное окно кнопку в обработчике нажатия которой написать - Applet.Close;


Vladimir Kladov ©   (18.09.23 15:54[5]


> Моей программе требуется возможность ее корректно завершения
> другой программой.

Тогда надо обрабатывать wm_close, и корректно завершать открытые модальные диалоги. Или проще - сделать требуемые действия (например, деактивировать иконку в трее) и вызвать TerminateApplet,


AndreyRus ©   (19.09.23 11:19[6]


> Тогда надо обрабатывать wm_close, и корректно завершать открытые модальные диалоги.

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

function TMainForm.MainFormMessage(var Msg: TMsg; var Rslt: Integer): Boolean;
begin
 if Msg.message = WM_CLOSE then
 begin
   // Если активное окно модальное, то закрыть его.
  if ModalForm <> nil then ModalForm.Form.Free; // Не работает
 end;
end;


Vladimir Kladov ©   (19.09.23 14:32[7]

А если ModalForm.Perform(WM_CLOSE, 0 0); ?


AndreyRus ©   (19.09.23 16:07[8]


> А если ModalForm.Perform(WM_CLOSE, 0 0); ?

Точно так же. Исключение в строке Applet.DF.fModalForm := nil функции TControl.ShowModal


RusSun ©   (20.09.23 04:32[9]

https://disk.yandex.ru/d/sMK7MIBEtY4QnQ


RusSun ©   (20.09.23 06:14[10]

Версия KOL v3.23.5
Delphi Borland® Delphi® for Microsoft® Windows™ Version 10.0.2166.28377 Update 1 Copyright © 2005 Borland® Software Corporation. All Rights Reserved.

>[4] "Предполагаю, что смоделировать эту ошибку можно, бросив на модальное окно кнопку в обработчике нажатия которой написать - Applet.Close;"
Однооконное приложение> с кнопкой вызова "модального окна" = 'Button1' >На кнопке -> «Закрыть модальное окно и закрыть приложение»


RusSun ©   (20.09.23 06:17[11]

procedure clickbutton2(Sender:PControl; var mouse:TMouseEventData);
begin
 Form2.ModalResult := 1;
 Form2.Close;
 Applet.Close
end;


Applet.Close при условии, что  «Applet» - "физически" есть на форме


RusSun ©   (20.09.23 09:28[12]

form2:=NewForm(Applet,'Form2').SetClientSize( 400, 200 ).CenterOnParent;
Button2 :=NewButton( form2, 'Закрыть модальное окно и закрыть приложение' ).SetSize( 381, 0 ).CenterOnParent;
Button2.OnClick:=TonEvent(MakeMethod(nil,@clickbutton2));
form2.showmodal;

Да. showmodal забыл.  и тогда появляется Runtime error 216 at 004043FC


RusSun ©   (20.09.23 10:46[13]

Если убрать Applet? То ошибки нет.

{Unit1_1.inc}
{ KOL MCK } // Do not remove this line!

procedure NewForm1( var Result: PForm1; AParent: PControl );
begin

 {$IFDEF KOLCLASSES}
 Result := PForm1.Create;
 {$ELSE OBJECTS}
 New( Result, Create );
 {$ENDIF KOL CLASSES/OBJECTS}
 Result.Form := NewForm( AParent, 'Form1' ).SetPosition( 8, 8 );
 Result.Form.Add2AutoFree( Result );
   Result.Form.SetClientSize( 555, 397 );
   Result.Form.Font.FontHeight := -11;
   Result.Button1 := NewButton( Result.Form, 'Button1' ).SetSize( 121, 0 ).CenterOnParent;
     Result.Button1.OnClick := Result.Button1Click;
   Result.Form.CenterOnParent;

end;

//unit unitModWinCrash1
{ KOL MCK } // Do not remove this line!
{$DEFINE KOL_MCK}
unit unitModWinCrash1;

interface

{$IFDEF KOL_MCK}
uses Windows, Messages, KOL {$IF Defined(KOL_MCK)}{$ELSE}, mirror, Classes, Controls, mckCtrls,
 mckObjs, Graphics {$IFEND (place your units here->)};
{$ELSE}
{$I uses.inc}
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, mirror;
{$ENDIF}

type
 {$IF Defined(KOL_MCK)}
 {$I MCKfakeClasses.inc}
 {$IFDEF KOLCLASSES} {$I TForm1class.inc} {$ELSE OBJECTS} PForm1 = ^TForm1; {$ENDIF CLASSES/OBJECTS}
 {$IFDEF KOLCLASSES}{$I TForm1.inc}{$ELSE} TForm1 = object(TObj) {$ENDIF}
   Form: PControl;
 {$ELSE not_KOL_MCK}
 TForm1 = class(TForm)
 {$IFEND KOL_MCK}
   KOLProj: TKOLProject;
   KOLForm: TKOLForm;
   Button1: TKOLButton;
   procedure Button1Click(Sender: PObj);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1 {$IF Defined(KOL_MCK)} : PForm1 {$ELSE} : TForm1 {$IFEND} ;
  form2,Button2:pcontrol;

{$IFDEF KOL_MCK}procedure NewForm1( var Result: PForm1; AParent: PControl );{$ENDIF}
implementation
{$IF Defined(KOL_MCK)}{$I Unit1_1.inc}{$ELSE}{$R *.DFM}{$IFEND}
procedure clickbutton2(Sender:PControl; var mouse:TMouseEventData);
begin
 Form2.ModalResult := 1;
  Form2.Close;

   Form1.Form.Close
  //Applet.Close
end;
procedure TForm1.Button1Click(Sender: PObj);
begin

form2:=NewForm(nil,'Form2').SetClientSize( 400, 200 ).CenterOnParent;
Button2 :=NewButton( form2, 'Закрыть модальное окно и закрыть приложение' ).SetSize( 381, 0 ).CenterOnParent;
Button2.OnClick:=TonEvent(MakeMethod(nil,@clickbutton2));
form2.showmodal;

end;

end.


AndreyRus ©   (20.09.23 11:11[14]

У меня эта ошибка проявляется и без компонента Applet на форме.


AndreyRus ©   (20.09.23 12:04[15]


> Да. showmodal забыл.  и тогда появляется Runtime error 216 at 004043FC


Я заметил интересную особенность - даже без showmodal в вашем примере приложение "падает" с вероятностью около 50%. Причем, если поставить брекпоинт на Applet.Close и когда отладчик остановит исполнение на этой строке продолжить выполнение то ошибка никогда не проявляется. Тут, на мой взгляд, присутствует какая то плавающая "ошибка", зависящая от временных задержек.


Дмитрий К ©   (20.09.23 12:21[16]

Добрый день.
Тут я хотел написать что-нибудь умное, но не получается, поэтому вот код:
program project1;
{$APPTYPE GUI}
uses
 Windows, Messages, KOL;
type
 PMainForm = ^TMainForm;
 TMainForm = object(TObj)
   Form, Btn: PControl;
   TI: PTrayIcon;
   procedure BtnClick(Sender: PObj);
   procedure FormClose(Sender: PObj; var Accept: Boolean);
   procedure TIMouse(Sender: PObj; Message: Word);
 end;
type
 PModalForm = ^TModalForm;
 TModalForm = object(TObj)
   Form, Btn: PControl;
   procedure BtnClick(Sender: PObj);
 end;

var
 MainForm: PMainForm;
 ModalForm: PModalForm;
 AppClosing: Boolean;

{ TModalForm }

procedure TModalForm.BtnClick(Sender: PObj);
begin
 AppClosing := true;
 Form.ModalResult := 2;
end;

{ TMainForm }

procedure TMainForm.BtnClick(Sender: PObj);
begin
 ModalForm.Form.ShowModal;
 if AppClosing then
   Form.Close
 else
   ModalForm.Form.Hide;
end;

procedure TMainForm.FormClose(Sender: PObj; var Accept: Boolean);
begin
 if AppClosing then
   Exit;
 if ModalForm.Form.Visible then
 begin
   Accept := False;
   AppClosing := True;
   ModalForm.Form.ModalResult := 2;
 end;
end;

procedure TMainForm.TIMouse(Sender: PObj; Message: Word);
begin
 if Message = WM_LBUTTONUP then
 begin
   Form.Perform(WM_CLOSE, 0, 0);
 end;
end;

begin
 Applet := NewApplet('Test');
 MainForm := New(PMainForm, Create);
 with MainForm^ do
 begin
   Form := NewForm(Applet, 'MainForm');
   Form.Add2AutoFree(MainForm);
   btn := NewButton(Form, 'Modal');
   btn.OnClick := BtnClick;
   Form.OnClose := FormClose;
   TI := NewTrayIcon(Form, LoadIcon(0, PKOLChar(IDI_APPLICATION)));
   TI.OnMouse := TIMouse;
   Form.Add2AutoFree(TI);
 end;
 ModalForm := New(PModalForm, Create);
 with ModalForm^ do
 begin
   Form := NewForm(Applet, 'ModalForm');
   Form.Add2AutoFree(ModalForm);
   Form.Visible := False;
   btn := NewButton(Form, 'Close');
   btn.OnClick := BtnClick;
 end;

 AppClosing := False;
 Run(Applet);
end.  


RusSun ©   (20.09.23 18:57[17]

to Дмитрий К: Великолепно! да, слов мало. Всё чётко.


AndreyRus ©   (20.09.23 21:40[18]

to Дмитрий К: Огромное спасибо! Ваш вариант решения проблемы отлично работает! У меня в программе несколько десятков модальных окон. Ваш способ требует переписывания каждого вызова модального окна, что несколько обременительно. К тому же логика работы с модальными окнами у меня различна, что потребует еще дополнительных усилий для изменения существующего кода. Методом проб и ошибок я нашел более простой способ. Для его использования требуется добавить в проект директиву условной компиляции  USE_SETMODALRESULT и добавить в обработчик закрытия главной формы нижеследующий код:

procedure TMainForm.MainFormClose(Sender: PObj; var Accept: Boolean);
begin
 if MyModalForm <> nil then
 begin
   Accept:= False;
   MyModalForm.Form.ModalResult:= -1;
   Form.Close;
 end;
end;

Этот способ тоже не без недостатка, так как при наличии большого кол-ва модальных окон придётся добавлять код для каждого модального окна и поддерживать его актульность при добавлении новых.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо