Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.02.26;
Скачать: [xml.tar.bz2];

Вниз

Многопоточность в DLL, отрисовка в приложении   Найти похожие ветки 

 
sally   (2006-01-12 18:40) [0]

Есть класс от TThread. Класс простейший: поиск файлов по диску. Отображать необходимо текущий файл и отрисовывать необходимую информацию. Но есть "но": передавать при создании объетка Canvas нельзя. Для "визуализации" процесса нужно использовать интерфейсы.

 IVisualizer = interface
   procedure Progress(AFile: string);
 end;

 TFileSearch = class(TThread)
 private
   FVisualizer: IVisualizer;
 protected
   procedure DoVisualize;
   procedure BuildFileList(const APath: string);
   procedure Execute; override;
 public
   constructor Create(AVisualizer: IVisualizer; const APath: string);
 end;

 TVisualizer = class(TForm, IVisualizer)
   procedure Progress(AFile: string);
 end;

procedure TFileSearch.Execute;
begin
 BuildFileList(FPath);
end;

procedure TFileSearch.BuildFileList(const APath: string);
...
begin
 ....
 /// Поиск файлов
  Synchronize(Draw);
  ....
end;

procedure TFileSearch.Draw;
begin
 // Если использовать просто напрямую Canvas, то все ок
 // Canvas.TextOut(10, 100, CurrentFile);
 //
 FVisualizer.Progress(CurrentFile);
 // При таком варианте возникает Exception
end;

procedure TForm1.Progress(AFile: string);
begin
 Canvas.TextOut(10, 100, AFile);
end;

Реально ли эту проблему обойти? Если да, то как?


 
simpson ©   (2006-01-12 21:03) [1]

IMHO, изврат полный.

Есть IVisualizer. Ну и пусть его реализация думает, как вывести информацию на форму. Никакого использования Synchronize здесь быть не должно. Все действия по синхронизации - только в IVisualizer.Progress.

В качестве обоснования приведу пример - завтра тебе сказали выводить информацию не на форму, а, скажем, в файл. Здесь уже синхронизация с VCL-потоком не нужна, а никуда не денешься - она у тебя жестко прибита.

Или твой поток из GUI-приложения перекочевал в сервис. То же самое.

Ни о каких Canvas поток, производящий поиск файлов, конечно же, знать не должен. "Мухи отдельно - котлеты отдельно". (С)

По поводу Exception - давай текст исключения, тип исключения и код реализации IVisualizer. Телепатически сегодня не угадыватеся что-то.


 
Digitman ©   (2006-01-13 08:12) [2]

А DLL здесь причем ?
Всуе упомянута или как ?


 
sally   (2006-01-13 10:52) [3]

> simpson
>IMHO, изврат полный.
Изврат в чем? В том как устроен обмен между DLL и приложением?
Exception: Canvas does not allow drawing

>код реализации IVisualizer

procedure TForm1.Progress(AFile: string);
begin
Canvas.TextOut(10, 100, AFile);
end;

>Digitman
В DLL реализован поиск файлов.

Каким образом еще можно реализовать обмен данными между  DLL(Service, Application)? Кроме разве что SendMessage ничего в голову не приходит. И имеет ли этот вариант(с Interface) право на жизнь?


 
Digitman ©   (2006-01-13 11:30) [4]


> В DLL реализован поиск файлов


т.е. класс  TFileSearch объявлен и реализован в DLL ?


 
sally   (2006-01-13 11:35) [5]

>Digitman
Да


 
Digitman ©   (2006-01-13 11:43) [6]

каков смысл вынесения сабжа в ДЛЛ ?

твоя ДЛЛ по твоей идее м.б. использована НЕ только Делфи-программами ?


 
sally   (2006-01-13 11:48) [7]

смысл в том, чтобы при изменении интерфейса основного приложения, не нужно было бы изменять DLL.


 
Digitman ©   (2006-01-13 11:57) [8]

я еще раз спрашиваю : твоя ДЛЛ по твоей идее м.б. использована НЕ только Делфи-программами ?

это КРАЙНЕ важно.


 
sally   (2006-01-13 11:59) [9]

>Digitman
Только Delphi-программами. Я бы даже сказал, что только своей программой(90%).


 
Digitman ©   (2006-01-13 12:06) [10]

В твоих хост-приложениях, потенциально использующих эту ДЛЛ, могут фигурировать множество форм, класс каждой из которых реализует этот интерфейс ?


 
sally   (2006-01-13 12:20) [11]

А в чем принципиальная разница? Несколько


 
Digitman ©   (2006-01-13 12:31) [12]


> в чем принципиальная разница?


ради одного-единственного класса, реализующего тот самый интерфейс. выёживаться с интерфейсами нет никакого резона.


 
sally   (2006-01-13 12:34) [13]

Как сделать не "выежываясь"?
И в чем заключается "выеживание"? Что нужно сделать, чтобы этот метод заработал?


 
Digitman ©   (2006-01-13 12:59) [14]

TMyCallback = procedure(AFile: string);

TFileSearch = class(TThread)
private
  FPath: String;
  FCallback: TMyCallback;
protected
  procedure Execute; override;
public
  constructor Create(ACallback: TMyCallback; const APath: string);
end;
..

constructor TFileSearch.Create;
begin
 FPath := APath;
 FCallback := ACallback;
 inherited Create(False);
end;

procedure TFileSearch.Execute;
begin
..
/// Поиск файлов
 FCallback(Currentfile);
..
end;


 
sally   (2006-01-13 13:11) [15]

>Digitman
Спасибо. Но в чем проблема с использованием интерфейсов?


 
Digitman ©   (2006-01-13 13:30) [16]


> в чем проблема с использованием интерфейсов?


проблема - в ошибке в 17-й строке


 
han_malign ©   (2006-01-13 17:34) [17]

Какой Canvas, какой Draw - это и без потоков работать не будет...
SendMessage(<control>.Handle, CM_INVALIDATE, 0, 0) без всяких Syncronize, и в OnDraw доступ к защищенному критической секцией полю(SendMessage вне критической секции, иначе deadlock)...


 
simpson ©   (2006-01-13 19:54) [18]

sally   (13.01.06 10:52) [3]

В чем изврат, описано в моем посте. Даже с примером.
Ошибка в проектировании. Если есть "нечто", предназначенное для выполнения "чего-то", то пусть это "нечто" и занимается своими делами.

Поток ищет файлы - пусть ищет. Его задача - найти файл и "дернуть" метод интерфейса. Все. Что делает интерфейс, поток волновать недолжно. И как он это делает, тоже потоку фиолетово.

Реализация интерфейса должна рисовать статистику в GUI - вот пусть рисует и сама заботится о том, как обеспечить потокобезопасность.

В твоем же примере это делается в потоке. Почему так делать не нужно, я пояснил на примере с сервисом.

Почему так делать необходимо:
1. Соблюдается принцип модульности проекта.
2. Функционал модулей четко разделен по области применения и не зависит от реализации самих модулей.
3. Synchronize - это в VCL. Завтра тебе нужно будет сделать то же самое без VCL. Либо используя другой framework. Или вообще не на Delphi. Нужна универсальность.

Не согласен с критиками, предлагающими использовать коллбэки или механизм оконных сообщений. Интерфейсы - подход более универсальный, и, как показала практика, более жизнеспособный (.NET).

Автор вопроса, безусловно, не Нострадамус, и не может предсказать, что будет с проектом и как он будет развиваться. Поэтому механизм взаимодействия модулей проекта нужно продумать изначально. Если это - просто "для себя", то даже в этом случае нужно учиться грамотно проектировать приложения - дальше будет проще.

Автору рекомендую почитать это:
http://rsdn.ru/article/patterns/patterns.xml

Да и вообще будут не лишними все статьи этого раздела.

ЗЫ. Автор? Приведи весь проблемный код. Почему у тебя это уже как минимум два человека выпрашивают?


 
sally   (2006-01-16 19:00) [19]

>simpson
Согласен, что с Callback - не лучший вариант.
>Автор? Приведи весь проблемный код

Код DLL

unit Unit2;

interface

uses
 Classes, untIntf, Windows;

type
 TCallback = procedure(AFile: string);

 TFileSearch = class(TThread)
 private
   FPath: string;
   FCurrentFile: string;
   FCallBack: IVisualizer;
 protected
   procedure Draw;
   procedure BuildFileList(const APath: string);
   procedure Execute; override;
 public
   constructor Create(ACallBack: IVisualizer; const APath: string);
   destructor Destroy; override;
   property CurrentFile: string read FCurrentFile write FCurrentFile;
 end;

implementation

{ TFileSearch }

procedure TFileSearch.BuildFileList(const APath: string);
var
 AFindFileData: TWin32FindData;
 AFileName: string;
 AFile: cardinal;
begin
 AFile := FindFirstFile(PAnsiChar(APath + "*"), AFindFileData);
 try
   if AFile <> INVALID_HANDLE_VALUE then
   repeat
     if AFindFileData.cFileName[0] = "." then Continue;
     AFileName := APath + string(AFindFileData.cFileName);
     CurrentFile := AFileName;
     FCallBack.Progress(CurrentFile);
     if (AFindFileData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0 then
       BuildFileList(AFileName + "\");
   until not FindNextFile(AFile, AFindFileData);
 finally
   Windows.FindClose(AFile);
 end;
end;

constructor TFileSearch.Create(ACallBack: IVisualizer; const APath: string);
begin
 FPath := APath;
 FCallBack := ACallback;
 inherited Create(True);
end;

destructor TFileSearch.Destroy;
begin
 inherited;
end;

procedure TFileSearch.Draw;
begin
 //FVisualizer.Progress(CurrentFile);
end;

procedure TFileSearch.Execute;
begin
 BuildFileList(FPath);
end;

end.

unit untIntf;

interface

type
 IVisualizer = interface
 ["{2C787F2F-C3AF-4B0E-977E-15CC0E1C8B24}"]
   procedure Progress(AFile: string);
 end;

implementation

end.

type
 TVisualizer = class(TForm, IVisualizer)
   Button1: TButton;
   Button2: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 private
   { Private declarations }
   FFileSearch: TFileSearch;
   procedure Progress(AFile: string);
 public
   { Public declarations }
 end;

var
 Visualizer: TVisualizer;

implementation

{$R *.dfm}
uses
 untLoadLib;

{ TForm1 }

procedure TVisualizer.Button1Click(Sender: TObject);
begin
 with TFileSearch(GetProc(Self, "c:\")) do
   Resume;
end;

procedure TVisualizer.Button2Click(Sender: TObject);
begin
 with TFileSearch(GetProc(Self, "d:\")) do
   Resume;
end;

procedure TVisualizer.Progress(AFile: string);
begin
  if SameText(AFile[1], "C") then
   Canvas.TextOut(10, 100, AFile)
 else
   Canvas.TextOut(10, 200, AFile);
 Application.ProcessMessages;
end;

Все собственно. Это только заготовка. На ней я и застопорился.


 
simpson ©   (2006-01-16 23:31) [20]

1.  Непонятно назначение свойства

property CurrentFile: string read FCurrentFile write FCurrentFile;

К этому свойству есть 2 обращения, причем из объекта того же класса, где свойство объявлено. При этом read- и write-методов как таковых нет.
Т. о., обращения к полю класса хватило бы:

FCallBack.Progress(AFileName);


2. Перегрузка деструктора, у которого тело состоит из вызова деструктора предка, не оправдана:

destructor TFileSearch.Destroy;
begin
inherited;
end;


3. Обработку исключений в потоках никто не отменял. В Execute должна присутствовать конструкция вида

try
...
except
...
on E: ....
...
end


4. Зачем создавать suspended-поток в данном случае?

5. Вообще, странный способ создавать объекты:

with TFileSearch(GetProc(Self, "c:\")) do

Так будет лучше:

with TFileSearch.Create(GetProc(Self, "c:\")) do


6. Кто отменил необходимость синхронизации и для чего вызов Application.ProcessMessages??

procedure TVisualizer.Progress(AFile: string);
begin
 if SameText(AFile[1], "C") then
  Canvas.TextOut(10, 100, AFile)
else
  Canvas.TextOut(10, 200, AFile);
Application.ProcessMessages;
end;


Где хотя бы вызов Lock и UnLock для Canvas?

 Canvas.Lock;
 try
   Canvas.TextOut(...);
 finally
   Canvas.Unlock;
 end;


Читаем справку по Canvas и Application.ProcessMessages.

В общем, до DLL пока не дошли ))). Рекомендую сделать это пока в одном проекте.


 
sally   (2006-01-24 16:58) [21]

>simpson
>Кто отменил необходимость синхронизации

А поподробней пожалуйста. Где в главной форме нужно делать синхронизацию и как?



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2006.02.26;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.039 c
2-1139171652
asd
2006-02-05 23:34
2006.02.26
действие ActionManager1


1-1138221604
_цуи_
2006-01-25 23:40
2006.02.26
embeddedwb (документация)


3-1135669029
DELORAC
2005-12-27 10:37
2006.02.26
Как получить из базы Oracle тексты создания таблиц?


2-1139826347
pupapumQ
2006-02-13 13:25
2006.02.26
Из delphi в excel


15-1138667087
Petr V. Abramov
2006-01-31 03:24
2006.02.26
Россияне не должны стать ИТ-батраками





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский