Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

корректное завершение [Delphi, Windows]


Страницы:   1 2

matroskin66 ©   (2007-09-11 19:41:00) 

здравствуйте. использую KOL для написания dll. в программе вызываю процедурку, показывающую форму из dll. форма отображается не модально. использую следующий код:

procedure ShowForm;
begin
if Applet <> nil then Applet.Free;
Applet := nil;
AppletTerminated := false;
Applet := NewApplet('');
NewMyForm(MyForm, Applet);
MyForm.Form.Show;
Applet.Visible := false;
Run(Applet);
Applet.Free;
Applet := nil;
AppletTerminated := false;
end;


А теперь суть проблемы. Если закрыть форму, и выгрузить dll, всё будет хорошо. Но если выгружать dll не закрывая KOL форму, то вылетает ошибка и программа вырубается :( Пробовал перед выгрузкой использовать метод MyForm.Form.Close но всё равно ошибка остаётся. Пожалуйста подскажите как быть.


Delphuk   (2007-12-23 17:56:00) [1]

Помню, но к сожалению мне это не по силам :(


Vladimir Kladov   (2007-12-23 17:29:00) [2]

А я уже предлагал. Асм-вставкой сделать, помните?


Delphuk   (2007-12-23 16:53:00) [3]

Тогда нужно искать другой выход, не через потоки. т.к. я просто не могу обойтись без call'ов. Остаётся только самый первый вариант, при котором всё отлично работает, но необходимо ручками закрывать окно. Пришли к тому, с чего начали :) Владимир, у вас есть ещё какие-нибудь предложения?


Vladimir Kladov   (2007-12-23 16:47:00) [4]

Как я и подумал: вы пытаетесь напрямую вызывать callback в хостовом приложении. Но из другого потока этого делать не следует - последствия непредсказуемы. Вариант с потоком подойдёт только для случая, когда между формой в dll и хостовым приложением нет прямых call'ов до самого закрытия формы.


Delphuk   (2007-12-23 16:14:00) [5]

Вот обработчик по дабл клику:

procedure TSettingsForm.LVMouseDblClk(Sender: PControl;
 var Mouse: TMouseEventData);
begin
if LV.LVCount < 1
then
  exit;

if (LV.LVCurItem = LV.LVFocusItem)
then
  RQ_OpenContactInfo(Int2Str(LV.LVItemData[LV.LVFocusItem]));
end;


А вот сама процедура из апи хост приложения:

procedure RQ_OpenContactInfo(uin: String);
begin
callStr(char(PM_CMD) + char(PC_SHOWINFO) + _istring(uin));
end;


P.S.
В ListView находится один столбец с данными вида: Name(string)/Uin(integer)


Delphuk   (2007-12-23 16:05:00) [6]

Вызываю процедуру из плагинного апи хост приложения (вызов окна с некоторой информацией). Там ошибок точно нет.


Vladimir Kladov   (2007-12-23 15:53:00) [7]

а что вы делаете в ondblclick?


Delphuk   (2007-12-23 14:08:00) [8]

Всё же оказалось не так всё гладко, как хотелось бы. Теперь после обработки события ОнДаблКлик в ListView, который находится на форме (которая вызывается в потоке) происходит ошибка, хост приложение валится или ругается на нехватку ресурсов. Возвращаю всё как было (без потоков), работает на ура :(


Delphuk   (2007-12-23 11:20:00) [9]

Владимир, заменил строчку TerminateThread(HThread,0); на HThread := 0; (поток и так норм зам закрывается, в конце процедурки написано же ExitThread(0); ) В общем вроде бы сейчас всё нормально, глюков и вылетов пока не заметил. Но правильный ли подход?


Vladimir Kladov   (2007-12-23 10:24:00) [10]

Ладно посмотрю, но мне сейчас срочно надо по магазинам с семьёй - искать новогодние прибамбасы для сына типа костюма, для ёлки типа гирлянды...

Сразу: я сказал, каак правильно поток завершать. Так у вас как минимум лик ресурсов может случиться. TerminateThread - это "последний выстрел", в том числе на API если поток делается. Поток должен сам себя закончить, это единственный правильный способ.


Delphuk   (2007-12-23 09:48:00) [11]

Владимир, смотрите как я делаю:


var
 SettingsForm {$IFDEF KOL_MCK} : PSettingsForm {$ELSE} : TSettingsForm {$ENDIF} ;
 CanShow: Boolean = true;
 AnswerList: PStrList;

 // переменные для потока
 thID: DWORD;
 HThread: THandle;

procedure ShowSettings; stdcall;
.............................................
//процедура создания и показа моего окна
procedure ShowSettings; stdcall;
begin
CanShow := false;
if Applet <> nil then Applet.Free;
Applet := nil;
AppletTerminated := false;
Applet := NewApplet('');
NewSettingsForm(SettingsForm, Applet);
SettingsForm.Form.Show;
Applet.Visible := false;
Run(Applet);
Applet.Free;
Applet := nil;
AppletTerminated := false;
CanShow := true;
ExitThread(0);
end;
.......................................
//это процедурка, обработчик нажатия кнопки вызова формы плагина
procedure OnButtonLeft(Handle: Integer; X,Y: Integer);
begin
if CanShow
then
  HThread:= CreateThread(nil,0,@ShowSettings,nil,0,thID); //запускаем в потоке процедуру создания и показа формы
else
  SettingsForm.Form.Show; //если форма открыта, то передаём ей фокус
end;
..................
//процедура которая вызывается при получении уведомления об отключении плагина
procedure OnFinalize;
begin
if HThread <> 0
then
  begin
   if not CanShow
   then
     SettingsForm.Form.Close;
   TerminateThread(HThread,0);
   MessageBox(0,'unload','dfdf',MB_ICONINFORMATION);
  end;
end;


Владимир, пожалуйста подскажите что изменить или покажите пример, как можно сделать по-другому.


Vladimir Kladov   (2007-12-23 06:54:00) [12]

Вообще, я так понимаю, проблема корректного завершения потока? Думаю, надо послать потоку WM_QUIT, затем сделать thread.Wait;, после чего ему можено говорить Free, и возвращаться в хост-программу.


Vladimir Kladov   (2007-12-23 03:31:00) [13]

Не могу сейчас, нет Delphi под рукой. (Смешно даже).


Delphuk   (2007-12-23 02:23:00) [14]

Владимир Кладов, так ничего и не получается :( Пожалуйста, помогите справиться с этой ситуацией. Только из-за этого бага не выпускаю плагин в паблик.


Delphuk   (2007-12-13 10:31:00) [15]

Хорошо, сразу после сдачи сессии попробую работу с потоками, потом отпишусь :)

P.S.
Самым минимум знания асма конечно же есть (как то даже проигрываени песенки "кузнечик" писал на чистом асме)


Vladimir Kladov   (2007-12-11 16:06:00) [16]

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

Честно если, я не знаю, как можно без минимального знания асма что-то серьёзное сделать. Надо же хотя бы теоретически представлять, в какие команды код с Паскаля превратится. Ведь Паскаль - это просто макроассемблер, просто навороченный.


Delphuk   (2007-12-11 12:49:00) [17]

Понятно. Правда в асме я не силён и вставок сделать не смогу. Да к тому же интересно, как можно из самой же библиотеки заставить программу выгрузить эту же библиотеку? Попутно возник вопрос, а как можно вообще безболезненно завершить этот цикл обработки Run(Applet) ?


Vladimir Kladov   (2007-12-09 15:07:00) [18]

А разница-то какая, закрываете вы форму или нет. Результат тот же - в стеке адрес возврата на цикл обработки сообщений Run. В общем, вы просто не пытаетесь представить себе, что происходит, кто кого и когда вызывает. Смотрите:

Главный цикл обработки сообщений в хост-приложении что-то взывал после чего загрузилась dll, сработал Run(Applet), и

начал работать цикл обработки сообщени в процедуре Run. То, что форма немодальная означает лишь, что DispatchMessage может вызывать отсюда обработчики окон хост-приложения, но они все вызываются из этого цикла. В том числе тот код, который решил выгрузить DLL.

Если такой обработчик выгрузит DLL, пусть даже вы и закроете форму, управление всё равно вернётся на код, который есть только  DLL. А раз DLL выгружена, то по этим адресам уже никакого кода нет.

И ожидание AppletTermunated в OnFinalize ничего не даст, возвращаться надо всё равно в код из DLL.

Возможное решение: Не дать выгружать DLL из хоста (например, ещё раз вызвать LoadLibrary). Пи желании выгрузиться самим можно после Run( Applet ), вызвав FreeLibrary дважды (Дважды - потому что и еслиLoadLibrary вызвана дважды). Но второй раз - только через асм, т.к. возвращаться из FreeLibrary можно будет только в хост-приложение. Обычная команда CALL неприменима, нужно в стек загнать правильный адрес возврата, и сделать Jmp. Без асм-вставки тут не обойтись.

Наверное, можно было избежать всего это, не создавая цикл обработки сообщений (не запуская Applet) в DLL, но так почему-то не получилось N лет назад. Может сейчас получится, если попробовать, не знаю.


Delphuk   (2007-12-09 14:13:00) [19]

Под "выгружать dll не закрывая KOL форму" я имел ввиду, что если из хост-приложения отключать плагин (в плагин посылается сообщение, что он сейчас будет отключен. В результате чего выполняется процедура OnFinalize, в которой я проверяю, открыта или нет форма и если нужно, то закрываю форму. dll'ка не выгружается, пока весь код процедуры OnFinalize не будет выполнен), то в случае с VCL никаких проблем нет, а с KOL происходит ошибка. Попробую поэксперементировать с AppletTerminated.


Vladimir Kladov   (2007-12-09 13:54:00) [20]

Тогда я не понимаю вот это ваше утверждение (жирным - я выделил):

А теперь суть проблемы. Если закрыть форму, и выгрузить dll, всё будет хорошо. Но если выгружать dll не закрывая KOL форму, то
вылетает ошибка и программа вырубается :( Пробовал перед выгрузкой использовать метод MyForm.Form.Close но всё равно ошибка
остаётся. Пожалуйста подскажите как быть.

Я думаю, что надо сделать всё правильно. И как минимум дождаться завершения цикла обработки сообщений (условие AppletTerminated = true).


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо