| 
| 
 | Вопрос # 2 926/ вопрос открыт / | 
 |  Доброго времени суток, уважаемые эксперты!Возникла такая проблема: есть модуль (код в приложении) сканирования сети. Если модуль запихнуть в exe то все нормально, никаких проблем, а вот если этот модуль запихнуть в Dll тогда возникает проблема. В чем собственно проблема: процедуры сканирования в потоке, если модуль в библиотеке, то поток запускается, но тока и не завершается( ждал очень долгое время, но так и не дождался когда завершится); если же модуль в exe то все нормаль, сканирование проходит и поток завершается...причем довольно быстро...
 Помогите разобраться в чем причина....
 Приложение:Переключить в обычный режим unit Unit1; interface uses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls, ComCtrls, Winsock, ImgList, ShellAPI; const       type  TDemoThread = class(TThread)  private    TreeNetWrk: TTreeNode;    TreeDomain: TTreeNode;    TreeServer: TTreeNode;    TreeShares: TTreeNode;    Param_dwType: Byte;    Param_dwDisplayType: Byte;    Param_lpRemoteName: String;    Param_lpIP: String;  protected    procedure Execute; override;    procedure Scan(Res: TNetResource; Root: boolean);    procedure AddElement;    procedure Stop;  end;   TForm1 = class(TForm)    Button1: TButton;    TreeView1: TTreeView;    StatusBar1: TStatusBar;    ImageList1: TImageList;    procedure Button1Click(Sender: TObject);    procedure TreeView1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure TreeView1DblClick(Sender: TObject);  private    Thread: TDemoThread;  end; var  Form1: TForm1; implementation {$R *.dfm} function GetIPAddress(NetworkName: String): String;var Error: DWORD; HostEntry: PHostEnt; Data: WSAData; Address: In_Addr;begin  Delete(NetworkName, 1, 2);  Error:=WSAStartup(MakeWord(1, 1), Data);  if Error = 0 then  begin    HostEntry:=gethostbyname(PAnsiChar(NetworkName));    Error:=GetLastError;    if Error = 0 then    begin      Address:=PInAddr(HostEntry^.h_addr_list^)^;      Result:=inet_ntoa(Address);    end    else     Result:='Unknown';  end  else    Result:='Error';  WSACleanup;end; { TDemoThread } procedure TDemoThread.Execute;var  R:TNetResource;begin  inherited;  Priority := tpIdle;  FreeOnTerminate := True;  Resume;  Scan(R, True);  TreeDomain := nil;  TreeServer := nil;  Synchronize(Stop);end; procedure TDemoThread.Scan(Res: TNetResource; Root: boolean);var hEnum: Cardinal; nrResource: array[0..512] of TNetResource; dwSize: DWORD; numEntries: DWORD; I: DWORD; dwResult: DWORD;begin  if Root then    dwResult := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,      0, nil, hEnum)  else    dwResult := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,      0, @Res, hEnum);  if dwResult = NO_ERROR then  begin    dwSize := SizeOf(nrResource);    numEntries := DWORD(-1);                                   // ERROR_NO_MORE_ITEMS    if WNetEnumResource(hEnum, numEntries, @nrResource, dwSize) = NO_ERROR then    begin      for i := 0 to numEntries - 1 do      begin        if Terminated then Break;        with nrResource[i] do        begin          Param_dwType := dwType;          Param_dwDisplayType := dwDisplayType;          Param_lpRemoteName := lpRemoteName;          if Param_dwDisplayType = RESOURCEDISPLAYTYPE_SERVER then            Param_lpIP := GetIPAddress(Param_lpRemoteName);        end;        if Assigned(nrResource[i].lpRemoteName) then          Synchronize(AddElement);        Scan(nrResource[i], false);      end;    WNetCloseEnum(hEnum);    end;  end;end; procedure TDemoThread.AddElement;begin  Application.ProcessMessages;  case Param_dwDisplayType of    RESOURCEDISPLAYTYPE_NETWORK:    begin      TreeNetWrk := Form1.TreeView1.Items.Add(nil, Param_lpRemoteName);      TreeNetWrk.StateIndex := 1;    end;    RESOURCEDISPLAYTYPE_DOMAIN:    begin      TreeDomain := Form1.TreeView1.Items.AddChild(TreeNetWrk, Param_lpRemoteName);      TreeDomain.StateIndex := 2;    end;    RESOURCEDISPLAYTYPE_SERVER:    begin      TreeServer := Form1.TreeView1.Items.AddChild(TreeDomain, Param_lpRemoteName + ' IP: ' +
Param_lpIP);      TreeServer.StateIndex := 3;    end;    RESOURCEDISPLAYTYPE_SHARE:    begin      TreeShares := Form1.TreeView1.Items.AddChild(TreeServer, Param_lpRemoteName);      TreeShares.StateIndex := 3 + Param_dwType;    end;  end;end; procedure TDemoThread.Stop;begin  Form1.StatusBar1.Panels[1].Text := STR_STOPPED;  Form1.Button1.Caption := STR_START;  Form1.Button1.Enabled := True;  Form1.Tag := 0;end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Tag := 0;end; procedure TForm1.Button1Click(Sender: TObject);begin  Tag := Tag + 1;  if (Tag mod 2) = 1 then  begin    TreeView1.Items.Clear;    StatusBar1.Panels[1].Text := STR_STARTED;    Button1.Caption := STR_STOP;    Thread := TDemoThread.Create(False);  end  else  begin    StatusBar1.Panels[1].Text := STR_END;    Button1.Enabled := False;    Thread.Terminate;  end;end; procedure TForm1.TreeView1Click(Sender: TObject);begin  if Assigned(TreeView1.Selected) then    StatusBar1.Panels[0].Text := '   ' + TreeView1.Selected.Text  else    StatusBar1.Panels[0].Text := STR_FIELD;end; procedure TForm1.TreeView1DblClick(Sender: TObject);var  Str: String;begin  if Assigned(TreeView1.Selected) then  begin    Str := TreeView1.Selected.Text;    if Copy(Str, 1, 2) <> '\' then Exit;    if Pos(' IP:', Str) <> 0 then      ShellExecute(Handle, 'explore', PChar(Copy(Str, 1, Pos(' IP:', Str))), nil, nil, SW_SHOW)    else      ShellExecute(Handle, 'explore', PChar(Str), nil, nil, SW_SHOW);  end;end; end.
|  |   Вопрос задал: Ученый (статус: 8-ой класс)Вопрос отправлен: 19 июня 2009, 09:14
 Состояние вопроса: открыт, ответов: 0.
 |  
 Мини-форум вопросаВсего сообщений: 10; последнее сообщение — 19 июня 2009, 18:21; участников в обсуждении: 2. 
|   | Вадим К (статус: Академик), 19 июня 2009, 11:34 [#1]:Поток сам себя   Resume;? Это бессмысленная команда. Если поток её выполняет, что он выполняется, зачем его запускать снова.
 >>Synchronize(Stop);
 У потока есть чудное событие OnTerminate, которое выполняется по факту завешения потока в контексте главного потока.
 Попробуйте для начала закоментировать
 Synchronize(AddElement);
 и посмотреть, будет ли вообще работать.
 А потом найти на этом сайте мою статью о логах и "угадать", в какой строке программа падает.
 Дело в том, что если произойдет исключение в главном потоке, то Вы его увидите (делфи обрабатывает исключения в главном потоке), а вот в Ваших потоках Вы должны сами. А только исключение - поток падает. возможно глобальный try except в процедуре execute Вас спасет...
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Ученый (статус: 8-ой класс), 19 июня 2009, 15:34 [#2]:Вадим К. попробую сделать как вы сказали. но вот только я не пойму одного: почему этот код работает в exe, а если эту форму кинуть в либу и загружать от туда, то не работает, тоесть поток падает. в чем раздница, что в exe будет выполняться, что в из либы грузиться? |  
|   | Вадим К (статус: Академик), 19 июня 2009, 16:02 [#3]:а dll работает с формой в dll? Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Ученый (статус: 8-ой класс), 19 июня 2009, 16:07 [#4]:Дело обстоит так....есть форма, на которую и выводятся результаты сканирования, весь код какраз находится в юните этой формы...что же сделал я: я взял эту форму с юнито и запихнул в либу, и загружаю ее от туда. ни код ничего не менял, просто тупо положил в длл...но вот почему в exe все работает норм, а в длл не хочет .... |  
|   | Вадим К (статус: Академик), 19 июня 2009, 16:41 [#5]:во первых, форма в длл - плохо. Но можно чуть подлечить костылями с подменой Application. Но Synchronize в этом случае (форма в длл) работает не адекватно (он о такой ситуации не знает).
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Ученый (статус: 8-ой класс), 19 июня 2009, 17:05 [#6]:а почему форма в длл плохо? |  
|   | Вадим К (статус: Академик), 19 июня 2009, 17:25 [#7]:Что бы понять, почему это так, надо разобраться, как приложение на делфи управляет своими форма. Скажем так, в приложении есть небольшой набор объектов, которые управляют состоянием всех форм. Когда появляется длл с своими формами, мы имеем два набора таких объектов. Они управляют формами независимо (при этом могут быть две модальные формы, неадекватно редактируемый StringGrid, или что то в таком стиле).И пока они между собой не перекликаются, всё кое-как работает. Но как только какая то форма попадает под управление двух "менеджеров форм", начинаются чудеса. (у семи нянек дитя без глазу  ) Synchronize наивно считает(хотя и на законных основаниях), что такой менеджер один. И тут начинаются чудеса.
 Надо также понимать, как Synchronize работает.
 В целом, это очень большая и запутанная тема. Как то может соберусь и распишу сумароное поведение. Но что бы не иметь приключения, лучше не делать формы в длл, а вместо Synchronize пользоваться другими методами синхронизации, например sendmessage|postmessage.
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Ученый (статус: 8-ой класс), 19 июня 2009, 17:34 [#8]:тоесть, лучше формы хранить в exe, а в длл запихнуть лишь некоторые функции и процедуры? |  
|   | Вадим К (статус: Академик), 19 июня 2009, 18:10 [#9]:да. длл для того и нужны, что бы хранить код, который либо используется многими программами, либо код, который нужнен редко (сюда и плагины тоже относяться). Я не понимаю идеи вставлять весь код в длл только с целью "что бы было" или "так круто".
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Ученый (статус: 8-ой класс), 19 июня 2009, 18:21 [#10]: Цитата: с целью "что бы было" или "так круто" наверно вы правы....
 |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |