Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 2 926

/ вопрос открыт /

Доброго времени суток, уважаемые эксперты!
Возникла такая проблема: есть модуль (код в приложении) сканирования сети. Если модуль запихнуть в exe то все нормально, никаких проблем, а вот если этот модуль запихнуть в Dll тогда возникает проблема. В чем собственно проблема: процедуры сканирования в потоке, если модуль в библиотеке, то поток запускается, но тока и не завершается( ждал очень долгое время, но так и не дождался когда завершится); если же модуль в exe то все нормаль, сканирование проходит и поток завершается...причем довольно быстро...
Помогите разобраться в чем причина....

Приложение:
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7. Dialogs, StdCtrls, ComCtrls, Winsock, ImgList, ShellAPI;
  8.  
  9. const
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17. type
  18. TDemoThread = class(TThread)
  19. private
  20. TreeNetWrk: TTreeNode;
  21. TreeDomain: TTreeNode;
  22. TreeServer: TTreeNode;
  23. TreeShares: TTreeNode;
  24. Param_dwType: Byte;
  25. Param_dwDisplayType: Byte;
  26. Param_lpRemoteName: String;
  27. Param_lpIP: String;
  28. protected
  29. procedure Execute; override;
  30. procedure Scan(Res: TNetResource; Root: boolean);
  31. procedure AddElement;
  32. procedure Stop;
  33. end;
  34.  
  35. TForm1 = class(TForm)
  36. Button1: TButton;
  37. TreeView1: TTreeView;
  38. StatusBar1: TStatusBar;
  39. ImageList1: TImageList;
  40. procedure Button1Click(Sender: TObject);
  41. procedure TreeView1Click(Sender: TObject);
  42. procedure FormCreate(Sender: TObject);
  43. procedure TreeView1DblClick(Sender: TObject);
  44. private
  45. Thread: TDemoThread;
  46. end;
  47.  
  48. var
  49. Form1: TForm1;
  50.  
  51. implementation
  52.  
  53. {$R *.dfm}
  54.  
  55. function GetIPAddress(NetworkName: String): String;
  56. var
  57. Error: DWORD;
  58. HostEntry: PHostEnt;
  59. Data: WSAData;
  60. Address: In_Addr;
  61. begin
  62. Delete(NetworkName, 1, 2);
  63. Error:=WSAStartup(MakeWord(1, 1), Data);
  64. if Error = 0 then
  65. begin
  66. HostEntry:=gethostbyname(PAnsiChar(NetworkName));
  67. Error:=GetLastError;
  68. if Error = 0 then
  69. begin
  70. Address:=PInAddr(HostEntry^.h_addr_list^)^;
  71. Result:=inet_ntoa(Address);
  72. end
  73. else
  74. Result:='Unknown';
  75. end
  76. else
  77. Result:='Error';
  78. WSACleanup;
  79. end;
  80.  
  81. { TDemoThread }
  82.  
  83. procedure TDemoThread.Execute;
  84. var
  85. R:TNetResource;
  86. begin
  87. inherited;
  88. Priority := tpIdle;
  89. FreeOnTerminate := True;
  90. Resume;
  91. Scan(R, True);
  92. TreeDomain := nil;
  93. TreeServer := nil;
  94. Synchronize(Stop);
  95. end;
  96.  
  97. procedure TDemoThread.Scan(Res: TNetResource; Root: boolean);
  98. var
  99. hEnum: Cardinal;
  100. nrResource: array[0..512] of TNetResource;
  101. dwSize: DWORD;
  102. numEntries: DWORD;
  103. I: DWORD;
  104. dwResult: DWORD;
  105. begin
  106. if Root then
  107. dwResult := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,
  108. 0, nil, hEnum)
  109. else
  110. dwResult := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,
  111. 0, @Res, hEnum);
  112. if dwResult = NO_ERROR then
  113. begin
  114. dwSize := SizeOf(nrResource);
  115. numEntries := DWORD(-1); // ERROR_NO_MORE_ITEMS
  116. if WNetEnumResource(hEnum, numEntries, @nrResource, dwSize) = NO_ERROR then
  117. begin
  118. for i := 0 to numEntries - 1 do
  119. begin
  120. if Terminated then Break;
  121. with nrResource[i] do
  122. begin
  123. Param_dwType := dwType;
  124. Param_dwDisplayType := dwDisplayType;
  125. Param_lpRemoteName := lpRemoteName;
  126. if Param_dwDisplayType = RESOURCEDISPLAYTYPE_SERVER then
  127. Param_lpIP := GetIPAddress(Param_lpRemoteName);
  128. end;
  129. if Assigned(nrResource[i].lpRemoteName) then
  130. Synchronize(AddElement);
  131. Scan(nrResource[i], false);
  132. end;
  133. WNetCloseEnum(hEnum);
  134. end;
  135. end;
  136. end;
  137.  
  138. procedure TDemoThread.AddElement;
  139. begin
  140. Application.ProcessMessages;
  141. case Param_dwDisplayType of
  142. RESOURCEDISPLAYTYPE_NETWORK:
  143. begin
  144. TreeNetWrk := Form1.TreeView1.Items.Add(nil, Param_lpRemoteName);
  145. TreeNetWrk.StateIndex := 1;
  146. end;
  147. RESOURCEDISPLAYTYPE_DOMAIN:
  148. begin
  149. TreeDomain := Form1.TreeView1.Items.AddChild(TreeNetWrk, Param_lpRemoteName);
  150. TreeDomain.StateIndex := 2;
  151. end;
  152. RESOURCEDISPLAYTYPE_SERVER:
  153. begin
  154. TreeServer := Form1.TreeView1.Items.AddChild(TreeDomain, Param_lpRemoteName + ' IP: ' + Param_lpIP);
  155. TreeServer.StateIndex := 3;
  156. end;
  157. RESOURCEDISPLAYTYPE_SHARE:
  158. begin
  159. TreeShares := Form1.TreeView1.Items.AddChild(TreeServer, Param_lpRemoteName);
  160. TreeShares.StateIndex := 3 + Param_dwType;
  161. end;
  162. end;
  163. end;
  164.  
  165. procedure TDemoThread.Stop;
  166. begin
  167. Form1.StatusBar1.Panels[1].Text := STR_STOPPED;
  168. Form1.Button1.Caption := STR_START;
  169. Form1.Button1.Enabled := True;
  170. Form1.Tag := 0;
  171. end;
  172.  
  173. { TForm1 }
  174.  
  175. procedure TForm1.FormCreate(Sender: TObject);
  176. begin
  177. Tag := 0;
  178. end;
  179.  
  180. procedure TForm1.Button1Click(Sender: TObject);
  181. begin
  182. Tag := Tag + 1;
  183. if (Tag mod 2) = 1 then
  184. begin
  185. TreeView1.Items.Clear;
  186. StatusBar1.Panels[1].Text := STR_STARTED;
  187. Button1.Caption := STR_STOP;
  188. Thread := TDemoThread.Create(False);
  189. end
  190. else
  191. begin
  192. StatusBar1.Panels[1].Text := STR_END;
  193. Button1.Enabled := False;
  194. Thread.Terminate;
  195. end;
  196. end;
  197.  
  198. procedure TForm1.TreeView1Click(Sender: TObject);
  199. begin
  200. if Assigned(TreeView1.Selected) then
  201. StatusBar1.Panels[0].Text := ' ' + TreeView1.Selected.Text
  202. else
  203. StatusBar1.Panels[0].Text := STR_FIELD;
  204. end;
  205.  
  206. procedure TForm1.TreeView1DblClick(Sender: TObject);
  207. var
  208. Str: String;
  209. begin
  210. if Assigned(TreeView1.Selected) then
  211. begin
  212. Str := TreeView1.Selected.Text;
  213. if Copy(Str, 1, 2) <> '\' then Exit;
  214. if Pos(' IP:', Str) <> 0 then
  215. ShellExecute(Handle, 'explore', PChar(Copy(Str, 1, Pos(' IP:', Str))), nil, nil, SW_SHOW)
  216. else
  217. ShellExecute(Handle, 'explore', PChar(Str), nil, nil, SW_SHOW);
  218. end;
  219. end;
  220.  
  221. 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]:

Цитата:

с целью "что бы было" или "так круто"

наверно вы правы....

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:25
Выполнено за 0.03 сек.