Форум: "Основная";
Текущий архив: 2006.08.13;
Скачать: [xml.tar.bz2];
ВнизЭкспорт / импорт (dll) функций из класса Найти похожие ветки
← →
Leonid Troyanovsky © (2006-06-29 20:37) [160]
> Fay © (29.06.06 19:50) [159]
> Понимаю, у Вас найдутся дела и поинтереснее, но пока все
> стороны воздерживаются от примеров (которые можно "потрогать"),
> приходится верить (или нет) на слово.
Вот, когда я был маленький, я тоже каждый год ездил ..
пардон, мечтал о разных скинах-плагинах, динамически
подключаемых формах и пр.
И был очень рад, открыв для себя такую во всем замечательную
вещь как dll (уж про, например, dll hell, я тогда и понятия не имел).
Долго искал, мучился, эксперементировал с переменным успехом,
пока старшие товарищи не научили смотреть на вещи без розовых очков.
Эти принципы я усвоил, позволю их повторить:
1. использовать dll только тогда, когда без оной обойтись нельзя.
2. не использовать объекты в in, out & inside dll.
После & - это уже мои собс-ные выводы на базе определенного
эмпирического опыта воспроизведения трудноуловимых глюков.
Правда, примеры я не коллекционировал, бо, видимо, не
задумывался о их полезности в нынешней дискуссии.
Однако, неприятные ощущения от того опыта остались.
Они легко воспроизводятся при словах dll+OOP.
Кстати, я еще давно заметил, что сторонники dll+OOP обычно
напористы и агрессивны (маньякально-депрессивны -шут.)
Видимо, каждый из них проходит через "озарение" (И был очень рад..),
и искренне полагает, что все дельфийское сообщество прошло стороной.
Ну, а ларчик открывается просто.
MS не было нужды (= не было возможности) делать dll
объектно ориентированной.
Когда оные нужды созрели - появился и COM и .NET.
Какие уж тут, dll. Пора, IMHO, оставить старушку в покое :)
Извини, брат, за отсутствие кода,
театр закрывается, нас всех тошнит (с) Хармс.
--
Regards, LVT.
← →
Almaz © (2006-06-29 20:39) [161]Господа, позвольте уж и мне вставить реплику в Вашу милую беседу...
Оставив вопрос об экспорте/импорте объектов и классов из DLL, как уже решенный в этой теме, выскажусь по поводу использования классов внутри реализации функций DLL.
Во-первых, ИМХО, спорящие забыли упомянуть исключениях, представленных в Дельфи классом Exception. Даже при процедурном программировании их применение часто позволяет сильно упростить код, избавив его, например, от множества ветвлений при последовательности сложных проверок и т.п.
Во-вторых, позволю напомнить о такой "разновидности" DLL, как CPL. Дельфи предлагает реализовывать эти DLL на основе класса TAppletModule и, собственно, VCL. Вы предпочитаете писать CPL на WinAPI ? Я нет - мне дороже мое время.
В-третьих вся реализация COM-серверов в DLL в Delphi от начала и до конца строится на ООП. (хотя про СОМ разговор особый - это конечно же не классические DLL)
Теперь немного о приведенных выше аргументах против:
> Допустим даже, что у нас есть доводы за dll.
> Как, собс-но, мы должны применить ООП?
> Видимо:
> 1. Создать объект
> 2. Заполнить его поля некоторыми простых типами,
> переданными из хоста.
> 3. Сделать некоторые пассы.
> 4. Вернуть хосту нужные простые типы из полей.
> 5. Разрушить объект.
>
> Налицо некоторые overheads. Т.е., все это совершенно спокойно
> можно свести к неким преобразованиям простых типов,
Пока речь идет о классе типа TList - это да, это аргумент. Но вот есть у меня класс, ответственный за распознавание текста - его реализация занимает огромное число строчек кода и буде он мне понадобится в DLL мне и в голову не придет потратить несколько дней на выколупование отдельных процедур из этого класса - все равно, время, потраченное программой на создание/удаление экземпляра этого класса ничтожно по сравнением с исполнением задачи процедурой. Оптимизация должна быть разумной - разве я неправ ?
> без мучительных раздумий, как уследить за распределенной
> в длл памяти,
Разве в промежутке от 1 до 6 исполнение может быть прервано извне без завершения вызвавшего функцию потока ? А раз нет, то и никаких раздумий у нормального программиста не должно возникать.
> что будет, если будет повторный вызов в промежутке
> между 1 - 6 и т.д."
Собственно, ничего не будет, если поток создается и разрушается при каждом вызове.
Позволю себе немного обобщить - использование ООП внутри DLL, ИМХО, не привнесет никакого криминала, кроме некоторых накладных расходов связанных с соданием и разрушением объектов, которые имеет смысл учитывать лишь тогда, когда они соизмеримы со временем выполнения процедуры.
p.s. При создании DLL в Delphi через пункт New.., Delphi включает в нее модули SysUtils и Classes тем самым обуславливая создание как минимум 8 объектов ;)) Не будем считать программистов Borland"a такими уж дураками, не знающими , что "исполнение кода при этом самом detach отягощена некоторыми особенностями" ;)))
← →
Leonid Troyanovsky © (2006-06-29 20:57) [162]
> Almaz © (29.06.06 20:39) [161]
> Borland"a такими уж дураками, не знающими , что "исполнение
> кода при этом самом detach отягощена некоторыми особенностями"
> ;)))
Конечно, не дураки, но всего лишь люди.
Из той же BDE (царствие ей небесное)
уж никак не получилась классическая dll.
И иной раз приходилось таки перегружаться,
из-за некорректной ее финализации.
--
Regards, LVT.
← →
Almaz © (2006-06-29 21:05) [163]
> Конечно, не дураки, но всего лишь люди.
> Из той же BDE (царствие ей небесное)
> уж никак не получилась классическая dll.
Аминь ;))
> И иной раз приходилось таки перегружаться,
> из-за некорректной ее финализации.
Там проблем хватало и без финализации ;)
← →
Пусик © (2006-06-29 21:22) [164]Ну что же.
Пример я таки сделала.
Весьма схематично, но код рабочий.
Основной модуль:
unit ufMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm4 = class(TForm)
Button1: TButton;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
end;
TProcessFile=function(FilePath: DWORD): BOOL; stdcall;
var
Form4: TForm4;
HandleArray: array of THandle;
ProcArray: array of TProcessFile;
implementation
{$R *.dfm}
procedure GetFiles(const aPath: String;var aListFile: TStringList);
var
SR: TSearchRec;
tPath: String;
begin
{$WARN SYMBOL_PLATFORM OFF}
tPath := IncludeTrailingBackSlash(aPath);
if FindFirst(tPath+"\*.*",faAnyFile,SR)=0 then
begin
try
repeat
if (SR.Name=".") or (SR.Name="..") then Continue;
if (SR.Attr and faDirectory)<>0
then Continue
else aListFile.Add(tPath+SR.Name);
until FindNext(SR)<>0;
finally
Sysutils.FindClose(SR);
end;
end;
{$WARN SYMBOL_PLATFORM ON}
end;
procedure TForm4.Button1Click(Sender: TObject);
var
L: TStringList;
Ext: String;
i: Integer;
begin
L := TStringList.Create;
try
GetFiles("c:\temp",L);
for i := 0 to L.Count - 1 do
begin
Ext := AnsiUpperCase(ExtractFileExt(L[i]));
if Ext=".TXT" then ProcArray[0](DWORD(PChar(L[i])));
if Ext=".DBF" then ProcArray[1](DWORD(PChar(L[i])));
end;
finally
L.Free;
end;
end;
procedure TForm4.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeLibrary(HandleArray[0]);
FreeLibrary(HandleArray[1]);
end;
procedure TForm4.FormCreate(Sender: TObject);
var
H: THandle;
Proc: TProcessFile;
begin
SetLength(HandleArray,2);
SetLength(ProcArray,2);
H := LoadLibrary("Dll1\FType1.dll");
HandleArray[0] := H;
@Proc := GetProcAddress(H,"Process");
ProcArray[0] := @Proc;
H := LoadLibrary("Dll2\FType2.dll");
HandleArray[1] := H;
@Proc := GetProcAddress(H,"Process");
ProcArray[1] := @Proc;
end;
end.
← →
Пусик © (2006-06-29 21:23) [165]Реализация родительского класса:
unit uParentCLass;
interface
uses
classes;
type
TMainDLLClass=class
public
FFIlePath: String;
FL: TStringList;
constructor Create(const FilePath: String);
destructor Destroy; override;
function ProcessFile: Boolean; virtual;
end;
implementation
{ TMainDLLClass }
constructor TMainDLLClass.Create(const FilePath: String);
begin
FFIlePath := FilePath;
FL := TStringList.Create;
end;
destructor TMainDLLClass.Destroy;
begin
FL.Free;
inherited;
end;
function TMainDLLClass.ProcessFile: Boolean;
var
i: Integer;
begin
Result := False;
try
FL.LoadFromFile(FFIlePath);
for i := FL.Count - 1 downto 0 do
begin
if FL[i]="" then FL.Delete(i);
end;
FL.SaveToFile(FFIlePath);
Result := True;
except
end;
end;
end.
← →
Пусик © (2006-06-29 21:24) [166]DLL1:
library FType1;
uses
windows,
SysUtils,
Classes,
uParentClass in "..\uParentClass.pas";
type
TMainDLLClassType1=class(TMainDLLClass)
public
constructor Create(const FilePath: String);
function ProcessFile: Boolean; override;
end;
{ TMainDLLClassType1 }
constructor TMainDLLClassType1.Create(const FilePath: String);
begin
inherited Create(FilePath);
end;
function TMainDLLClassType1.ProcessFile: Boolean;
begin
inherited ProcessFile;
Result := True;
//Здесь обработка файла нужного типа.
end;
function Process(FilePath: DWORD): BOOL; stdcall;
var
Obj: TMainDLLClassType1;
begin
Result := False;
try
Obj := TMainDLLClassType1.Create(PChar(FilePath));
try
Result := Obj.ProcessFile;
finally
Obj.Free;
end;
except
end;
end;
exports
Process;
end.
← →
Пусик © (2006-06-29 21:25) [167]DLL2:
library FType2;
uses
windows,
SysUtils,
Classes,
uParentClass in "..\uParentClass.pas";
type
TMainDLLClassType2=class(TMainDLLClass)
public
constructor Create(const FilePath: String);
function ProcessFile: Boolean; override;
end;
{ TMainDLLClassType2 }
constructor TMainDLLClassType2.Create(const FilePath: String);
begin
inherited Create(FilePath);
end;
function TMainDLLClassType2.ProcessFile: Boolean;
begin
Result := True;
//Здесь обработка файла нужного типа.
end;
function Process(FilePath: DWORD): BOOL; stdcall; export;
var
Obj: TMainDLLClassType2;
begin
Result := False;
try
Obj := TMainDLLClassType2.Create(PChar(FilePath));
try
Result := Obj.ProcessFile;
finally
Obj.Free;
end;
except
end;
end;
exports
Process;
end.
← →
Пусик © (2006-06-29 21:26) [168]Прошу прощения, отступы(табуляция) обрезались и в последнем посте код не выделила.
← →
Fay © (2006-06-29 21:41) [169]2 Пусик
Приведённый пример слишком хорошо подходит для иллюстрации сказанного в [40]. Это развод?
З.Ы.
> TProcessFile=function(FilePath: DWORD): BOOL; stdcall;
Если не секрет, почему именно DWORD ?
← →
Пусик © (2006-06-29 21:45) [170]
> Если не секрет, почему именно DWORD ?
Чтобы не возникло воросов об использовании DLL с хост-программами на другом языке программирования. DWORD - native type
← →
Пусик © (2006-06-29 21:49) [171]
> Приведённый пример слишком хорошо подходит для иллюстрации
> сказанного в [40].
Что тебя сподвигло на такое суждение?
← →
Fay © (2006-06-29 21:57) [172]2 Пусик
> Чтобы не возникло воросов
А указатель-то чем не угодил?
> Что тебя сподвигло на такое суждение?
Не вижу ваще никакого смысла в создании классов TMainDLLClass-идов - всё равно всё свелось к нескольким версиям одной процедуры.
← →
Пусик © (2006-06-29 22:02) [173]
> всё равно всё свелось к нескольким версиям одной процедуры.
А шире глянуть? Это всего лишь пример, иллюстрирующий применение ООП в DLL. Реализация реальных классов будет намного сложнее.
> А указатель-то чем не угодил?
А какая разница для иллюстрации?
← →
Alx2 © (2006-06-29 22:15) [174]>Пусик © (29.06.06 22:02)
Итого - три независимых DLL.
Наследование в каждой начинается заново. Смысл?
← →
Alx2 © (2006-06-29 22:18) [175]Сорри. Две DLL. Но непринципиально это.
← →
Пусик © (2006-06-29 22:25) [176]>Alx2 © (29.06.06 22:15) [174]
Итого - три независимых DLL.
Наследование в каждой начинается заново. Смысл?
Ну это же пример, повторяю. Рельный проект будет намного сложнее.
Создан же пример для иллюстрации того, что ООП в DLL - совершенно нормальное дело.
← →
Alx2 © (2006-06-29 22:29) [177]> [176] Пусик © (29.06.06 22:25)
Я понимаю. Но смысла таки нет.
Если у нас A - предок B, C - его потомки, то в программе (классика) имеет место иерархия A, B(A), C(A).
У тебя, если покдючить обе DLL, получится
в первой: A1, B1(A1);
во второй: A2, B2(A2).
Причем A1<>A2
То есть имеем две совершенно чуждые друг другу ветви наследования.
Функционально A1=A2, но с точки зрения архитектуры A1<>A2. Смысл дублировать?
Вот примерно это я имел в виду.
← →
parovoZZ © (2006-06-30 04:22) [178]Удалено модератором
← →
Игорь Шевченко © (2006-06-30 10:56) [179]Пусик © (29.06.06 18:59) [156]
Уважаемое, примите лекарство от хамства, совет такой добрый.
← →
Пусик © (2006-06-30 11:23) [180]
> Игорь Шевченко © (30.06.06 10:56) [179]
> Пусик © (29.06.06 18:59) [156]
>
> Уважаемое, примите лекарство от хамства, совет такой добрый.
>
Ваши советы приберегите для LVT и прочая. Совет такой добрый.
← →
Игорь Шевченко © (2006-06-30 11:35) [181]Пусик © (30.06.06 11:23) [180]
Вместо того, чтобы флеймить, лучше бы матчасть почитать, право, пользы всяко больше будет.
← →
Fay © (2006-06-30 11:38) [182]Так... Добрались до сути. Собственно, разговор давно идёт в таком ключе, но форма изложения уже явно изменилась...
← →
Romkin © (2006-06-30 12:40) [183]Пусик © (29.06.06 21:25) [166] [167] Здесь я вижу первый способ, который я приводил в [129]. Ничего нового :)
Для реализации используется ООП.
<родительский класс-протокол>-MainDLL-->
<Дочерний класс-протокол1>-Prot1DLL
<Дочерний класс-протокол2>-Prot2DLL
...
<Дочерний класс-протоколN>-ProtNDLL
Периодически список обрабатываемых протоколов изменяется - одни устаревают и удаляются, новые появляются.
А интересен-то именно способ общения с объектами. Почему интересен? Очень просто: ну есть у нас система плагинов для подключения считывающих устройств. Вроде штрих-считывателей, картридеров и тд.Компонент + dll с определенным классом. Только я четко могу сказать, каким образом сделано: ActiveX. Соответственно, компонент регистрируется в категории, потом подгружается нужный, конфигурируется и идет работа.
Но это, как я уже говорил, не ООП :) Нет класса - общего предка плагина.
← →
Romkin © (2006-06-30 12:41) [184]Fay © (30.06.06 11:38) [182] Скучно :) Воинствующий дилетантизм, как всегда.
← →
Пусик © (2006-06-30 18:29) [185]
> Romkin © (30.06.06 12:41) [184]
> Fay © (30.06.06 11:38) [182] Скучно :) Воинствующий дилетантизм,
> как всегда.
Значит, использование ООП только этим исчерпывается?
Скажи, ты используешь обработку исключений в DLL?
← →
Пусик © (2006-06-30 18:29) [186]Удалено модератором
Примечание: На [6] недопонятый, на [7] недопонявший. На чем и закончим.
Страницы: 1 2 3 4 5 вся ветка
Форум: "Основная";
Текущий архив: 2006.08.13;
Скачать: [xml.tar.bz2];
Память: 0.8 MB
Время: 0.046 c