Форум: "Сети";
Текущий архив: 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]Да, все так и есть.
Вот попробовал безо всяких там Indylibrary 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.
Поэтому-то дедлока и не возникает. Это про ф-цию TerminateThreadThe 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.037 c