Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.05.16;
Скачать: CL | DM;

Вниз

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;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.023 c
11-1069436539
DDA
2003-11-21 20:42
2004.05.16
KOL SetFileTime?


6-1080576386
***ghost***
2004-03-29 20:06
2004.05.16
Еще один скрипт!


7-1074950103
Angel_Forever
2004-01-24 16:15
2004.05.16
Слежка за запускаемыми на ПК процессами


14-1082647358
SergP
2004-04-22 19:22
2004.05.16
Подскажите как правильно делать?


7-1081181563
alexsandri
2004-04-05 20:12
2004.05.16
господа !!! Каким образом установит сервис