Форум: "Основная";
Текущий архив: 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