Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
15-1153204722
Vendict
2006-07-18 10:38
2006.08.13
Fat32


15-1151760863
Roast
2006-07-01 17:34
2006.08.13
Ищу работу программиста-стажера в Москве (Delphi)


15-1152707829
harisma
2006-07-12 16:37
2006.08.13
Вордовский файл.


15-1152956535
PSPF2003
2006-07-15 13:42
2006.08.13
Эмулятор ОС


15-1152693914
Furyz-dimodim
2006-07-12 12:45
2006.08.13
Биллинг ... и учет траффика





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский