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

Вниз

Возвращение данных функцией из dll   Найти похожие ветки 

 
-=GaLaN=- ©   (2003-08-14 16:18) [0]

Каким образом функция, вызываемая из плагина, может вернуть список строк TStringList? Dll генерит этот список и его надо получить в программе. Но как?


 
Игорь Шевченко ©   (2003-08-14 16:20) [1]

Указатель на него вернуть :))


 
-=GaLaN=- ©   (2003-08-14 16:26) [2]

А можно пример кода? Декларация функции, как возвращать значение, и как его принимать в программе.


 
HolACost! ©   (2003-08-14 16:27) [3]

Я бы всётаки предложил в ДЛЛ передавать адрес обеъкта в который надо поместить сгенереный список из вызывающей функции...


 
-=GaLaN=- ©   (2003-08-14 16:39) [4]

Но как?


 
777 ©   (2003-08-14 16:40) [5]

Можно просто список строк передавать как PChar;
(если длл своя конечно :))
TStrings.GetText
TStrings.SetText


 
Digitman ©   (2003-08-14 16:41) [6]

function PlugInFunc: TStringList; export;
begin
Result:= TStringList.Create;
end;

...

var
sl: TStringList;
...
sl := PlugInFunc;
...
sl.Free;

p.s.
При условии, что и вызывающее приложение/библ-ка и вызываемая библ-ка-плагин собраны с опцией "Build with run-time packages"


 
Игорь Шевченко ©   (2003-08-14 16:47) [7]



program Exe;

uses
ShareMem,
Forms,
ExeMain in "ExeMain.pas" {Form1};

{$R *.RES}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
unit ExeMain;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;

var
Form1: TForm1;

implementation

function GetStringList : TStringList; external "Dll.dll";

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
List : TStringList;
I : Integer;
begin
List := GetStringList;
for I:=0 to Pred(List.Count) do
ListBox1.Items.Add(List[I]);
List.Free();
end;

end.


library dll;

uses
ShareMem,
SysUtils,
Classes,
DllMain in "DllMain.pas";

{$R *.RES}

exports
GetStringList index 1;
begin
end.

unit DllMain;

interface
uses
Classes;

function GetStringList : TStringList;

implementation

function GetStringList : TStringList;
begin
Result := TStringList.Create();
Result.Add("Item1");
Result.Add("Item2");
Result.Add("Item3");
Result.Add("Item4");
end;

end.


ShareMem является обязательным. Или Build with-time packages, как советует Digitman


 
Digitman ©   (2003-08-14 16:57) [8]

Игорь, шара-то зачем ? Не динамическая же структура возвращается... лишь бы VMT/RTTI и экземпляр менеджера памяти единые были у вызывающей и вызываемой сторон ... при BwRTP это условие как раз соблюдается и шара, imho, лишняя, ибо по sl.Free мы обращаемся к тем же самым сист.структурам, что и были использованы при конструировании

аргументируй ...


 
Юрий Федоров ©   (2003-08-14 16:57) [9]

Я думаю, что в данном случае обязательным является и ShareMem и Build with-time packages
поэтому сам поступил бы как 777 © (14.08.03 16:40) [5]


 
panov ©   (2003-08-14 17:00) [10]

exe:
-----
var
tL: TStringList;
begin
tL := TStringList(MyFunc(...)); //call myFunc
...
DelList(pointer(tL));

-----
dll
-----
function MyFunc(...):pointer;stdcall;
begin
Result := TStringList.Create;
...
end;

procedure DelList(p: pointer);stdcall;
begin
TStringList(p).Free;
end;


 
Игорь Шевченко ©   (2003-08-14 17:04) [11]

Digitman © (14.08.03 16:57) [8]

Шара затем, что передаются длинные строки и освобождение происходит в основной программе, а создание в DLL


 
reonid ©   (2003-08-14 17:04) [12]

я бы просто передал ДЛЛ callback-функцию типа

type
TAddStrProc = procedure(str: PChar);
//TAddStrProc = procedure(UserData: Pointer; str: PChar);
//TAddStrProc = procedure(str: PChar) of object;


 
Игорь Шевченко ©   (2003-08-14 17:08) [13]

Юрий Федоров © (14.08.03 16:57)

Дико извиняюсь, но это масло масленое :)


 
Digitman ©   (2003-08-14 17:10) [14]


> Игорь Шевченко


но ведь эти самые "длинные строки" уничтожаются только при sl.Free ! И при этом (при исполнении автоматически генерируемого кода деаллокации длинной строки) внутреннее обращение к FreeMem() происходит в контексте того же менеджера, к которому происходило обращение по GetMem(), когда эти строки создавались..


 
Юрий Федоров ©   (2003-08-14 17:18) [15]

>>Игорь Шевченко © (14.08.03 17:08) [13]
Я слегка погорячился :-(
Согласен с Digitman.
Только вот автор возможно не планировал включать BwRTP :-)


 
Игорь Шевченко ©   (2003-08-14 17:19) [16]

Digitman © (14.08.03 17:10)

> И при этом (при исполнении автоматически генерируемого
> кода деаллокации длинной строки) внутреннее обращение к
> FreeMem() происходит в контексте того же менеджера, к которому
> происходило обращение по GetMem(), когда эти строки создавались..


Неа :) Создаются они в MM DLL, а уничтожаются в MM EXEшника.

"This applies to all strings passed to and from your DLL--even those that are nested in records and classes."


 
Aleksey Pavlov ©   (2003-08-14 18:15) [17]

Хм. А как насчёт правила, что в каком модуле ресурсы распределяются, в том они и должны освобождаться? А не дай бог эту dll будут другие использовать... leak


 
-=GaLaN=- ©   (2003-08-14 18:25) [18]

А где вообще можно найти информацию по написанию dll для ламеров? Мне интересно, есть ли у библиотек код инициализации и выгрузки, как у классов, и если нет, то как организовать нечто подобное?


 
Digitman ©   (2003-08-15 10:07) [19]


> Игорь Шевченко


проведем маленький эксперимент :

var
ptr: PInteger;
mm: TMemoryManager;
...
GetMemoryManager(mm);
ptr := @mm;
showmessage(inttohex(ptr^, 8)); //GetMem
inc(ptr);
showmessage(inttohex(ptr^, 8)); //FreeMem

при условии BwRTP и отсутствии шарового MM ставим этот код в EXE и DLL и сравниваем адреса, по которым в ВАП процесса находятся ф-ции TMemoryManager.GetMem()/FreeMem(), потенциально вызываемые в контексте EXE и в контексте DLL при аллокации/деаллокации в том числе длинных строк


 
Игорь Шевченко ©   (2003-08-15 10:27) [20]

Digitman © (15.08.03 10:07)

> при условии BwRTP

Этим все сказано :) При этом условии MM находится в VCLxx.bpl и является общим для EXE и DLL. Мой пример без этого условия, от того и ShareMem

Aleksey Pavlov © (14.08.03 18:15)

На это правило есть ShareMem :))


 
Digitman ©   (2003-08-15 10:35) [21]


> Игорь Шевченко


здрасть, приехали !) ну так я конкретно о случае с BwRTP с самого начала и веду речь !) при котором шара необязательна)


 
Игорь Шевченко ©   (2003-08-15 10:42) [22]

Digitman © (15.08.03 10:35)

Дык, Сергей, я об том писал в конце Игорь Шевченко © (14.08.03 16:47)

Или - или. При BwRTP никакой Sharemem не требуется, так как MM один на всех.


 
Юрий Федоров ©   (2003-08-15 10:52) [23]

>>Игорь Шевченко © (15.08.03 10:42) [22]
:-)))
Так ведь нельзя без BwRTP передавать объекты :-) Так что вариант только один :-)


 
Digitman ©   (2003-08-15 10:54) [24]


> Игорь Шевченко


Ок.
Будем считать недоразумение исчерпанным)
Фразу "или - или" я, видимо, упустил из виду)


 
Игорь Шевченко ©   (2003-08-15 10:57) [25]

Юрий Федоров © (15.08.03 10:52)

Можно :) В моем примере же передается объект :)


 
Digitman ©   (2003-08-15 10:59) [26]


> Юрий Федоров


Совершенно верно. В контексте изначально поставленного вопроса катит только вариант с BwRTP


 
Digitman ©   (2003-08-15 11:03) [27]


> Игорь Шевченко


передается. Но первое же обращение к нему по полученной ссылке
for I:=0 to Pred(List.Count) do ..

возбудит EConvertError


 
Игорь Шевченко ©   (2003-08-15 11:47) [28]

Digitman © (15.08.03 11:03)

Не возбудит :) Можно мой код откомпилировать и запустить :)


 
Digitman ©   (2003-08-15 13:03) [29]


> Игорь Шевченко


Игорь, приношу публичные извинения.

действительно - код 100%-но работоспособный.
перестанет он работать лишь при первой же попытке тайпкастинга а-ля list : = GetStringList as TSomeStringListDescendant;
.
очевидность этого, думаю, ни у кого не вызовет сомнений.


 
Юрий Федоров ©   (2003-08-15 13:29) [30]

Я совсем перестал что-либо понимать...
То есть я правильно понял, что речь идет о сборке без BwRTP?

Во первых, при чем тут тайпкастинг под потомка, если создан реально именно TStringList - это не пройдет и в рамках одного модуля.
Во вторых, где гарантия, что Exe и Dll скомпилированы с одинаковыми директивами компилятора? Или имеется в виду частный случай, что именно для TStringList так делать можно и на него директивы не влияют?

Пример: Я передаю свой объект в библиотеку по ссылке, у него приватным полем запись (record), в Exe стоит {$A+}, в Dll {$A-}.
Это что, тоже будет работать?
Я согласен, что код Игоря скорее всего будет работать, но в принципе так делать нельзя, ИМХО.
Еще пример - мы компилируем Exe на Delphi3, а DLL на Delphi6. Будет такой код работать? Класс TStringList есть и там и там...
Или я что-то не так понял - поправьте меня тогда...


 
Игорь Шевченко ©   (2003-08-15 14:17) [31]

Юрий Федоров © (15.08.03 13:29)


> Пример: Я передаю свой объект в библиотеку по ссылке, у
> него приватным полем запись (record), в Exe стоит {$A+},
> в Dll {$A-}.
> Это что, тоже будет работать?


А вот это не будет работать ни при каких условиях, уважаемый :) Хоть как откомпилировать, с BwRTP или без них.

> Еще пример - мы компилируем Exe на Delphi3, а DLL на Delphi6.
> Будет такой код работать?

Будет. А вот с Run-time packages - гарантировано не будет, так как разные они для разных версий, runtime packages.


 
Юрий Федоров ©   (2003-08-15 14:31) [32]

>>>> Еще пример - мы компилируем Exe на Delphi3, а DLL на Delphi6.
>>Игорь Шевченко
>>Будет.

положение метода Get в VMT гарантированно совпадет ?
Да и сам VMT в том же месте окажется тоже гарантировано ?


 
Digitman ©   (2003-08-15 14:47) [33]


> Юрий Федоров



> если создан реально именно TStringList - это не пройдет
> и в рамках одного модуля


никто с этим и не спорит)

ну а вдруг такая вот ситуация возникнет при необходимости ? при шаре и без сквозного BwRTP ?

type
// декларация - во всех заинтересованных модулях
TMyStringList = class(TStringList)
...
end;

function GetStringList: TMyStringList;
begin
Result := TStringList.Create; // реально создан именно TStri
...
end;

...

var
List: TStringList;
..

List := GetStringList;
...

ShowMessage(List.ClassName); // "TMyStringList"

if List is TMyStringList then // условие не выполнится, хотя List реально есть TMyStringList
(List as TMyStringList).SomeProp := ...;


 
Игорь Шевченко ©   (2003-08-15 14:47) [34]


> положение метода Get в VMT гарантированно совпадет ?


Смотреть надо. Может и совпадет, у меня D3 под рукой нету. Если не совпадет, то тогда работать не будет.


> Да и сам VMT в том же месте окажется тоже гарантировано
> ?


А какая разница ? Виртуальные методы будут использовать истинную VMT объекта. Проблема может быть только в смещении виртуального метода относительно начала VMT. Если смещение одинаковое, то не вижу причины, чтобы не работать.

Впрочем, насколько я понимаю, в исходной задаче не стоит использование разных версий Delphi для EXE и для DLL, так что этот вопрос мы можем рассмотреть отдельно. При желании - за пивом :)


 
Юрий Федоров ©   (2003-08-15 15:18) [35]

>>Digitman © (15.08.03 14:47) [33]
Я понял. А почему не выполнится кастинг? Значит что-то все таки не так...
>>Игорь Шевченко © (15.08.03 14:47) [34]
Насчет пива - идея неплохая :-)
Ладно, бог с ним, с VMT, тут скорее дело в данных.
...
TStringList = class(TStrings)
private
FList: PStringItemList;
...
Имеем дело с указателем на массив записей (TStringItem).
В модуле Classes {$A...} нет.
In the {$A8} or {$A+} state, fields in record types that are declared without the packed modifier and fields in class structures are aligned on quad-word boundaries.
Что скажешь ?
Упрямый я, однако...


 
Игорь Шевченко ©   (2003-08-15 15:23) [36]

Юрий Федоров © (15.08.03 15:18)

Я скажу одно - в книгах пишут, что EXE и DLL нужно компилировать с одними и теми же опциями выравнивания. Или использовать ключевое слово packed в объявлении типа record или class.
Вот ведь стандартные библиотеки Windows вообще на C/C++ написаны, однако record"ы в них передаются без особых проблем, потому что слово packed указано при объявлении их типов.


 
Юрий Федоров ©   (2003-08-15 15:39) [37]

>>Игорь Шевченко
Кстати, "without the packed modifier and fields in class structures", то есть поля класса тоже могут выравниваться или не выравниваться в зависимости от {$A}?
Я всегда думал, что это относится только к Record"ам.
Ну вот в TStringItem они как раз packed и не написали :-(

Насчет пива надо бы мысль не потерять :-)


 
Digitman ©   (2003-08-15 15:55) [38]


> Юрий Федоров


> почему не выполнится кастинг


именно потому что экземпляры VMT - разные ... хоть они и одинаковы (в нашем предположении) , но имеют разные адреса в памяти

вот ключ к разгадке "граблей" :


procedure _AsClass;
asm
{ -> EAX left operand (class) }
{ EDX VMT of right operand }
{ <- EAX if left is derived from right, else runtime error }
TEST EAX,EAX
JE @@exit
MOV ECX,EAX
@@loop:
MOV ECX,[ECX]
CMP ECX,EDX // в нашем случае (тайпкастинг к наследнику, при упомянутых условиях) ECX никогда не будет равен EDX
JE @@exit // никогда не уйдем на @@exit
MOV ECX,[ECX].vmtParent
TEST ECX,ECX
JNE @@loop

{ do runtime error }
MOV AL,reInvalidCast
JMP Error // строго сюда попадаем

@@exit:
end;



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

Текущий архив: 2003.08.28;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.015 c
3-92009
ОченьТупой
2003-08-05 15:38
2003.08.28
поясните по автоинкрементому полю


7-92275
Kirill_S
2003-06-06 18:01
2003.08.28
как получить список программ свернутых в SysTray?


14-92223
Esu
2003-08-11 15:07
2003.08.28
Простая но прикольная задачка :)


14-92249
Омлет
2003-08-09 00:30
2003.08.28
Palladin, с днём рождения!


1-92109
Song
2003-08-15 11:48
2003.08.28
TVS_CHECKBOXES. Как определить что ветвь с галочкой?