Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.08.13;
Скачать: CL | DM;

Вниз

Экспорт / импорт (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;
Скачать: CL | DM;

Наверх




Память: 0.81 MB
Время: 0.06 c
3-1149327665
Dust
2006-06-03 13:41
2006.08.13
Пример работы с базой (хочу идеальный код)


15-1153306535
Prohodil Mimo
2006-07-19 14:55
2006.08.13
Есть ли Skype-плагин к Миранде?


2-1153836386
sirus
2006-07-25 18:06
2006.08.13
Освежение DBGRID-а


9-1132859186
Мортимер
2005-11-24 22:06
2006.08.13
и снова этот гадский :) DoCollision


2-1153863830
SerJaNT
2006-07-26 01:43
2006.08.13
Hex