|
Вопрос # 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]:
Цитата:
с целью "что бы было" или "так круто"
наверно вы правы....
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|