Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Вниз

IdUDPServer в dll   Найти похожие ветки 

 
alin   (2004-03-22 08:39) [0]

в dll находится форма на которой лежит IdUDPServer форма создаётся при загрузке dll,
при выгрузке её из памяти приложение зависает если свойство Active UDPServera установлено в True если установлено False то выгрузка проходит нормально, попытка в событии destroy формы установить false не помогает.

Помогине кто может, что я делаю не так!


 
Digitman ©   (2004-03-22 09:08) [1]

приведи текст обработчика OnUDPRead


 
alin   (2004-03-22 09:50) [2]

в OnUDPRead вообще ничего нет


 
Digitman ©   (2004-03-22 09:54) [3]

хорошо.
приведи текст, реализующий твой алгоритм работы с IdUDPServer, начиная с Active := True и вплоть до Active := False


 
alin   (2004-03-22 09:55) [4]

вот текст:

library MyDll;

uses
 SysUtils,Classes, Forms,
 Windows, Dialogs,
 Unit2 in "Unit2.pas" {Form2};

{$R *.res}
var
 frmMain1 : TForm2;

procedure MyDLLProc(Reason: Integer);
begin
 if Reason = DLL_PROCESS_DETACH then begin
   frmMain1.Free;
 end;
end;

begin
 DLLProc := @MyDLLProc;
 frmMain1:=TForm2.Create(Application);
 frmMain1.Show;
end.

на форме только две кнопки

procedure TForm2.Button1Click(Sender: TObject);
begin
 UDPS.Active:=true;
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
 UDPS.Active:=false;
end;


вот вызывающая форма:
unit Unit1;

interface

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

type
 TForm1 = class(TForm)
   Button1: TButton;
   Button2: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;
 f : LongWord;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 f:=Loadlibrary("MyDll.dll");
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 FreeLibrary(f);
end;

end.


 
Digitman ©   (2004-03-22 10:44) [5]

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

попробуй для проверки след.код :

procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
 if UDPS.Active then
   begin
    UDPS.Active := False;
    Sleep(AcceptWait);
   end;
  frmMain1.Free;
end;
end;


 
alin   (2004-03-22 12:11) [6]

нет не помогает всё равно зависает на всегда


 
Digitman ©   (2004-03-22 12:26) [7]

procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
if UDPS.Active then
  UDPS.Active := False;
 frmMain1.Free;
end;
end;

поставь на отмеченной строке брейкпойнт, поймай его, сделай шаг (F8), убедись, что "вис" происходит именно на этой строке .. в противном случае убедись что эта строчка не вызывает исключения (равно как и следующая)

причин "виса" может быть всего 2 : либо в ходе деактивации listener thread не завершается либо при деактивации происходит искл.ситуация

только не спрашивай, что такое брейкпойнт, что такое "шаг" и пр. - это страшная тайна


 
alin   (2004-03-22 14:04) [8]

да зависает именно при нажатии F7 на этой выделенной строчке

будем дальше искать


 
Digitman ©   (2004-03-22 14:19) [9]

проверь, нет ли исключения

procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
if UDPS.Active then
 try
  UDPS.Active := False;
 except
  on e:exception do
    ShowMessage(e.classtype + " " + e.message);
 end;
frmMain1.Free;
end;
end;


 
alin   (2004-03-23 05:20) [10]

просто зависает без всякого исключения на UDPS.Active:=false;

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


library MyDll;
uses
 SysUtils,Classes, Forms,
 Windows, Dialogs, IdUDPServer, IdBaseComponent, IdComponent,
 IdUDPBase, IdUDPClient, IdSocketHandle;

{$R *.res}
var
 UDPS: TIdUDPServer;

procedure MyDLLProc(Reason: Integer);
begin
 if Reason = DLL_PROCESS_DETACH then begin
   if UDPS.Active then begin
     try
       UDPS.Active:=false;
     except
       on e:exception do
         ShowMessage(e.classtype.ClassName + " " + e.message);
     end;
   end;
   UDPS.Free;
 end;
end;

begin
 DLLProc := @MyDLLProc;
 UDPS:=TIdUDPServer.Create(Application);
 UDPS.DefaultPort:=21888;
 UDPS.BroadcastEnabled:=true;
 UDPS.Active:=true;
 ShowMessage("Load Ok");
end.


 
Verg ©   (2004-03-23 07:47) [11]

Нельзя этого делать в DllProc. Нельзя делать UDPS.Active:=false;
На DLL_PROCESS_DETACH происходит завершение кодового потока UDP сервера, для чего системе надо вызвать DLL_THREAD_DETACH этой же самой DLL-ки. "Патовая" ситуация
DLL_PROCESS_DETACH ожидает, когда завершится поток, а поток завершится не может, так как нужно вызвать DLL_THREAD_DETACH, что произойдет только после завершения DLL_PROCESS_DETACH.

Спецы по WINAPI могут объяснить это более внятно, но суть в том, что в DllProc завершать потоки и ожидать их завершения нельзя - приводит к DeadLock.


 
Verg ©   (2004-03-23 08:21) [12]

Да, все так и есть.
Вот попробовал безо всяких там Indy

library DllUDP;
uses
 SysUtils,
 Classes,
 Windows;
 
type
 TMyThread = class( TThread )
 public
   procedure Execute; override;
 end;

var
 MyT : TMyThread;

procedure TMyThread.Execute;
begin
 while not Terminated do
   Sleep(1000);
 messageBeep($FFFF);
end;

procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
  if MyT <> nil then
  begin
    MyT.Terminate;
    MyT.WaitFor;
  end;
  FreeAndNil(MyT);
end;
end;

begin
DLLProc := @MyDLLProc;
MyT := TMyThread.Create(false);
end.


При попытке выгрузить Dll-ку (FreeLibrary) приходит DeadLock на MyT.WaitFor.
DLLProc вызывается c DLL_PROCESS_DETACH и мы завершаем поток. Поточная ф-ция-то завершается, но его Handle не переходит в сигнальное состояние, т.к. для завершение потока необходимо вызывать DLL_THREAD_DETACH для всех DLL-ек процесса, но поток процесс уже находится в DLLProc одной из этих DLL-ек....однако
Only one thread in a process can be in a DLL initialization or detach routine at a time.

Но самое прикольное происходит при зваершении процесса, когда мы закрываем процесс, предварительно НЕ вызвав FreeLibrary....
Я пока не понимаю.... но тот поток (MyT) просто как бы "исчезает" (не объект, а его кодовый контекст) из системы, что видно в DLLProc при DLL_PROCESS_DETACH, если открыть окно Threads у отладчика. Однако его Handle установлен в сигнальное состояние.
Надо че-нить почитать....


 
Digitman ©   (2004-03-23 08:58) [13]


> Verg ©   (23.03.04 08:21) [12]


а попробуй при автовыгрузке (т.е. без явного FreeLibrary) "поймать" DLL_THREAD_DETACH ... и тут же посмотреть, CurrentThreadId = MainThreadId ?


 
Verg ©   (2004-03-23 09:02) [14]

[13] Digitman ©   (23.03.04 08:58)

А не происходит DLL_THREAD_DETACH. Да и с чего бы? Ведь ф-цию ExitThread никто не вызывал в этом случае. Я так понимаю, что тут происходит какое-то насильственное убиение потока типа TerminateThread.
Во всяком случае очень похоже на то.


 
Digitman ©   (2004-03-23 09:23) [15]


> Verg ©   (23.03.04 09:02) [14]


ты про какое терминирование процесса говоришь ? Штатное (ExitProcess) или аварийное (TerminateProcess) ? в первом случае д.б. тот же дедлок - процесс ведь не м.б. завершен без завершения всех его доп.код.потоков .. а во втором - конечно,  PROCESS/THREAD_DETACH ожидать бессмысленно


 
Verg ©   (2004-03-23 09:37) [16]

Я про штатное ExitProcess. Именно про штатное.
В приведенном мною примере в хост-приложеннии загрузи эту библиотеку (LoadLibrary), а затем закрой хост-приложение (на крестик нажми :)).
В DLLProc вызовется один раз с параметром DLL_PROCESS_DETACH и уже в нем того потока не будет существовать, как будь-то ему сделали TerminateThread.


 
Verg ©   (2004-03-23 09:39) [17]


> В DLLProc вызовется один раз с параметром DLL_PROCESS_DETACH
> и уже в нем того потока не будет существовать, как будь-то
> ему сделали TerminateThread.


Поэтому-то дедлока и не возникает. Это про ф-цию TerminateThread

The state of the thread object becomes signaled, releasing any other threads that had been waiting for the thread to terminate. The thread"s termination status changes from STILL_ACTIVE to the value of the dwExitCode parameter.


 
Digitman ©   (2004-03-23 09:58) [18]


> Verg ©   (23.03.04 09:39) [17]


возможно, при штатном завершении процесса система попросту не вызывает THREAD_DETACH .. но сам поток-то, imho, завершается штатно ! .. и здесь ведь неважно, где ему скомандовали "закругляться" - в обработчике ли PROCESS_DETACH либо в ином месте ..


 
Digitman ©   (2004-03-23 10:07) [19]


> Verg


вот тут Игорь Шевченко на умную мысль наводит, что при выполнении ExitProcess система автоматом вызывает DisableThreadLibraryCalls для каждого выгружаемого модуля

есть ли в этом плане смысл пробовать следующее :

procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
DisableThreadLibraryCalls(hInstance);
frmMain1.Free;
end;


 
Verg ©   (2004-03-23 10:17) [20]


> но сам поток-то, imho, завершается штатно ! ..


При штатном завершениее, но без выгрузки, ранее загружненной библиотеки, поток именно что завершается НЕ нормально. Это я вижу.
Опять же: поставь точку остонова на messageBeep в поточной ф-ции примера.
И закрой приложение штатно, но без FreeLibrary.
Не останавливается там. Т.е. поток просто прибивается.
И это не связано с DLL или там не с DLL. Так поступает система с любым потоком процесса, если он не сделал ExitThread (не завершился нормально) до ExitProcess главного. Я так понял.
Меня смутило другое - потоки она прибивает ДО вызовов DLL_PROCESS_DETACH во все DLL-ки.
Наверно это и логично.
Ну да ладно, дело не в том.
Т.е. при использовании серверных компонентов, основанных на многопоточной схеме (а это как правило сервера с синхронными сокетами) надо опасаться работать с ними в DLLProc, особенно в DLL_PROCESS_DETACH.

Для деактивации придется експортнуть ф-цию, которая бы останавливала все серверные потоки (IdUDPServer.Active := false, в данном случае). И эту ф-цию придется вызывать каждый раз перед FreeLibrary.


 
alin   (2004-03-23 10:35) [21]

видете ли эта dll предполагалась использоваться с Oracle Forms
причём чужим приложением и когда приложение будет закрыто я не могу знать и вызвать экспортируемую функцию для прибития потоков тоже не могу

единственное событие подвласное мне это DLL_PROCESS_DETACH


 
Digitman ©   (2004-03-23 11:11) [22]


> чужим приложением


я не знаю что такое "Формы Оракла ", но ты же как-то умудряешься заставить "чужое приложение" грузить твой модуль ? ... думаю, точно так же можно заставить это приложение и вызывать любые эксп.ф-ции из твоего модуля

даже если это нельзя сделать явно и документированно (т.е. по соглашениям с "чужим приложением"), это всегда можно сделать и с помощью различногго рода трюков, например, с внедрением хука


 
alin   (2004-03-23 11:21) [23]

просто в Oracle Forms пользовательские формы запускаются в оболочке Runtime если запустить сначала свою форму то в ней можно и загрузить dll она подгружается к Runtime и выгружается при его закрытии, просто хотелось по простому, придётся как всегда ...


 
Digitman ©   (2004-03-23 11:34) [24]


> если запустить сначала свою форму то в ней можно и загрузить
> dll


ну, наверно, у "твоей" формы есть какие-то события ? Загрузка ? Выгрузка ?

Мне не оч понятно, что мешает в событии загрузки "твоей" формы грузить твою же DLL, в событии выгрузки "твоей" формы сначала вызвать эксп.ф-цию этой DLL, а следом выгрузить и саму DLL ?


 
alin   (2004-03-23 12:05) [25]

Там все формы сделаны как дочернии окна Runtime моя форма после определённых действий закрывается на всегда и запускается форма чужого приложения, поэтому дальше все работают со старым приложением
а к нему подружены некоторые dll

в общем всё уже понятно и выкрутиться можно



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.038 c
1-1083305697
Expre$$
2004-04-30 10:14
2004.05.16
работа с компонентом Image


1-1082829945
kvazar
2004-04-24 22:05
2004.05.16
открытие файла


3-1082699903
vlad_vv
2004-04-23 09:58
2004.05.16
IBQuery+IBUpdateSQL выдает "Update Failed"


3-1082618842
avgur
2004-04-22 11:27
2004.05.16
Вопрос о клиент сервере


1-1083225929
Игорь
2004-04-29 12:05
2004.05.16
Когда я пишу в RichEdit текст вот такой





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский