Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
Внизпередача TStream из DLL Найти похожие ветки
← →
fford (2010-03-09 13:32) [0]Здравствуйте!
Вот нашел в инете такую статью
http://www.delphilab.ru/content/view/244/1/
решил попробовать передачу потока из DLL в программу.
Собственно
сделал DLL, где есть функция которая собирает все фалы из указанного каталога в один, формирует поток и передает его тому кто вызвал :)
function GetText(Path,FileName:Pchar):IStream; stdcall;
Var m:TMemoryStream;
st:TStrings;
Begin
m:=TMEmoryStream.Create;
st:=ReadFilesTo(StrPas(Path),StrPas(FileName)); //функция собственно собирает файлики и делает из них один, возвращая TStrings
st.SaveToStream(m);
result:=TStreamAdapter.Create(m, soOwned) as IStream;
st.Free;
End;
в программе описал следующую процедуру:
Procedure ExGetText(Path,FileName:String):TStrings;
Var lib:THandle;
f:Function(Path,FileName:PChar):IStream; stdcall;
mem:TStringList;
tmp:TExternStream;
Begin
lib:=LoadLibrary("c:\primer.dll");
if lib<>0 Then
Begin
@f:=GetProcAddress(lib,"GetText");
if @f<>nil Then
Begin
tmp:=TExternStream.Create(f(PChar(Path),PChar(FileName)));
mem:=TStringList.Create;
tmp.Position:=0;
mem.LoadFromStream(tmp);
mem.SaveToFile("c:\1.ttt");
tmp.Free;
end;
FreeLibrary(lib);
End;
End;
здесь класс TExternStream взят из статьи по ссылке описанной выше.
сделал каталог на диске покидал туда пару текстовиков
запустил процедуру на выполнение. Все прекрасно
на диске C: создался файл 1.ttt который содержит собственно конкатенацию файлов. т.е. все замечательно все работает
кроме одного
в строке FreeLibrary(lib);
программа вылетает с Access violation по такому-то адресу
немогу понять почему :(
я предполагаю что, когда я пытаюсь освободить память занятую этой DLL
кусок её, через IStream связан с основной программой (грубо)
но вроде бы по описанию
soOwned The stream is owned by the object that uses it (and exists solely for that object). The object that uses the stream frees the associated stream when it no longer needs to use the stream.
т.е. tmp.Free; должен освобождать поток, который создала DLL
где грабли? :)
← →
sniknik © (2010-03-09 13:42) [1]> где грабли? :)
в твоей интерпретации/реализации TExternStream, т.к. в статье все освобождается.
← →
fford (2010-03-09 13:52) [2]как я написал я взял класс из статьи
и освобождаю так же как и у автора в примере:var
aOut : TExternStream;
try
aOut := TExternStream.Create(strm);
Image1.Picture.Bitmap.LoadFromStream(aOut);
....
aOut.Free; //Тут уничтожиться поток созданный в Dll, так как указатель на aStream занулиться.
вот мой кодtmp:=TExternStream.Create(f(PChar(Path),PChar(FileName)));
mem:=TStringList.Create;
tmp.Position:=0;
mem.LoadFromStream(tmp);
mem.SaveToFile("c:\1.ttt");
tmp.Free;
f(PChar(Path),PChar(FileName)) возвращает IStream
из него копируется в mem
и tmp освбождается
← →
fford (2010-03-09 13:54) [3]причем все равно
делаю я tmp.free
или его комментирую
Access violation всеравно вылетает :(
← →
Медвежонок Пятачок © (2010-03-09 14:02) [4]зачем же интерфейсной ссылке делать фри?
← →
fford (2010-03-09 14:11) [5]
> зачем же интерфейсной ссылке делать фри?
а ей вроде никто и не делает фри
освобождается объект класса TExternStream
а его деструкторе интерфейсную ссылку обнуляют
что собственно и приводит к освобождению
т.к. на этот интерфейс уже нет ни одной ссылки
← →
fford (2010-03-09 14:25) [6]блин ничего не понимаю
по идее
работает так
1. создали поток в памяти DLL
2. создали интерфейс и связали его с потоком
3. программа получила данные из этого потока через переданный интерфейс
4. программа обнулила ссылку на интерфейс, т.е. его более никто не использует и он может спокойно быть разрушен
5. программа выгружает DLL освобождая память выделенную ей.
вот на п.5 вылетает ошибка
т.е. получается либо на интерфейс остались ссылки, но я при вызове деструктора класса обертки вроде обнуляю ссылку, либо программа не может выгружать DLL т.к. с куском памяти его связан интерфейс.
и как же тогда все по честному освободить ? ведь если я вызову много раз в программе буду вызывать эту длл с её функцией, то память будет утекать ...
или винда сама будет выгружать эту DLL при неиспользовании никем интерфейса ?
← →
Ega23 © (2010-03-09 14:27) [7]
> т.е. получается либо на интерфейс остались ссылки, но я
> при вызове деструктора класса обертки вроде обнуляю ссылку,
> либо программа не может выгружать DLL т.к. с куском памяти
> его связан интерфейс.
Собирать и exe и dll с единым менеджером памяти.
← →
fford (2010-03-09 14:32) [8]
> Собирать и exe и dll с единым менеджером памяти.
ды вариантов много то :)
как имнимум просто создавать файл из самой DLL а в программе его открывать
но было интересно попробовать именно с потоками
тем более у автора статьи все очень просто выглядит
а потоки действительно удобная вещь получаются для обмена большими массивами данных между DLL и программой
лучше вот подскажите
как быть с пунктами 4 и 5
т.е. как корректно освободить память из под потока
и DLL
:)
← →
Игорь Шевченко © (2010-03-09 14:36) [9]Ты, когда DLL делаешь, комментарий читай в файле проекта
← →
fford (2010-03-09 14:41) [10]
> Ты, когда DLL делаешь, комментарий читай в файле проекта
например?
← →
Сергей М. © (2010-03-09 14:43) [11]Покажи декларацию своего класса TExternStream и реализацию его конструктора Create ..
← →
fford (2010-03-09 14:46) [12]яже писал что ничего не изменял, взял его из статьи :)
вот то что у меня в проекте
:)
type
TExternStream = class(TStream)
protected
FSource : IStream;
procedure SetSize(const NewSize: Int64); override;
public
constructor Create(Source : IStream);
destructor Destroy; override;
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
end;
constructor TExternStream.Create(Source: IStream);
begin
inherited Create;
FSource := Source;
end;
← →
Ega23 © (2010-03-09 14:53) [13]
> > Ты, когда DLL делаешь, комментарий читай в файле проекта
>
> например?
File -> New Project -> DLL.
Там сгенерируется такой большой комментарий, который почему-то все удаляют не читая. А напрасно.
← →
Сергей М. © (2010-03-09 15:02) [14]
> а его деструкторе интерфейсную ссылку обнуляют
А вот в этом пока есть сомнения, хотя по идее оно так и должно быть, ибо интерфейсные типы относятся к типам с управляемым компилятором временем жизни
Попробуй в классе TExternStream перекрыть деструктор Destroy, чтобы обнилить интерфейсную FSource ссылку явно
← →
fford (2010-03-09 15:07) [15]
> Ega23 © (09.03.10 14:53) [13]
да читал я его и не единожды
:)
только вопрос то не в том
еще раз повторюсь, нашел статью где написано как очень просто передавать данные потока из DLL в программу и наоборот
соответственно без использования BORLNDMM.DLL
← →
Игорь Шевченко © (2010-03-09 15:26) [16]
> нашел статью где написано как очень просто передавать данные
> потока из DLL в программу и наоборот
> соответственно без использования BORLNDMM.DLL
Плохую статью нашел. По ссылке из нее:
"Как известно в Dll нельзя передавать объекты классов, а интерфейсы очень даже можно, при этом идеально сохраняется принцип инкапсуляции класса и объектный подход к разарботке приложений.
"
Это бред
← →
Сергей М. © (2010-03-09 15:27) [17]Ты уверен, что твоя реализация ф-ции ReadFilesTo чиста и непорочна ?
← →
fford (2010-03-09 15:32) [18]
> Игорь Шевченко © (09.03.10 15:26) [16]
не спорю
но не полностью
и главное что поток то передается :)
т.е. программа спокойно читает то что сформировала DLL
только вопрос в освобождении памяти
вот тут непонятно
← →
fford (2010-03-09 15:45) [19]
> Сергей М. © (09.03.10 15:27) [17]
я её закоментировал
сделал так
Var m:TMemoryStream;
st:TStrings;
Begin
m:=TMEmoryStream.Create;
//st:=ReadFilesTo(StrPas(Path),StrPas(FileName));
st:=TStringList.Create;
st.Append("dddddd");
st.Append("aaaaaaa");
st.SaveToStream(m);
result:=TStreamAdapter.Create(m, soOwned) as IStream;
st.Free;
рез-тат тотже :(
← →
Сергей М. © (2010-03-09 15:48) [20]
> fford (09.03.10 15:45) [19]
Приведи полный текст dll ..
← →
fford (2010-03-09 15:57) [21]ничего особенного :)
gttext я не привожу т.к. в функции закоментировал вызов
library primer;
uses
SysUtils,
Classes,
ActiveX,
GtText in "GtText.pas";
{$R *.res}
function GetName:PChar; stdcall;
Begin
result:="primer";
End;
function GetText(Path,FileName:Pchar):IStream; stdcall;
Var m:TMemoryStream;
st:TStrings;
Begin
m:=TMEmoryStream.Create;
//st:=ReadFilesTo(StrPas(Path),StrPas(FileName));
st:=TStringList.Create;
st.Append("dddddd");
st.Append("aaaaaaa");
st.SaveToStream(m);
result:=TStreamAdapter.Create(m, soOwned) as IStream;
st.Free;
End;
exports
GetName Index 1,
GetText Index 2;
begin
end.
← →
Сергей М. © (2010-03-09 16:04) [22]GetName в хост приложении используется ?
> GtText in "GtText.pas";
А где текст юнита GtText ? Что у тебя в нем творится ?
> ActiveX
Это зачем ?
← →
fford (2010-03-09 16:09) [23]
> Сергей М. © (09.03.10 16:04) [22]
GetName не используется
а GtText не важен можно его закоментировать
т.к. закоментирована строка
//st:=ReadFilesTo(StrPas(Path),StrPas(FileName));
в собственно той функции которая и вызывается из DLL
т.е. этот вызов я просто убрал и создаю TStringList, куда добавляю две строки
создаю поток, копирую туда эти строки
возвращаю интерфейс потока свзяанный с созданным потоком
и удаляю StringList за не надобностью, т.к. его копия уже есть в потоке.
ActiveX нужен
ибо там описан IStream
← →
Сергей М. © (2010-03-09 16:16) [24]> ActiveX нужен ибо там описан IStream
Из-да одного интерфейса я бы не стал тащить в проект целый юнит.
Вполне достаточно перетащить оттуда к себе декларации интерфейсов ISequentialStream и IStream (ну и Largeint, если Int64 глаз режет)
← →
fford (2010-03-09 16:24) [25]
> Сергей М. © (09.03.10 16:16) [24]
полностью согласен :)
← →
han_malign (2010-03-09 16:36) [26]
> result:=TStreamAdapter.Create(m, soOwned) as IStream;function GetText(Path,FileName:Pchar; out Stream:IStream): HRESULT; stdcall;
...
Result:= E_UNEXPECTED;
Stream:=TStreamAdapter.Create(m, soOwned) as IStream;//may raise exception
Result:= S_OK;
...
TExternStream = class(TStream)
...
constructor Create(var Source : IStream);
Результат - function GetText(...):IStream - временный экземпляр объекта типа интерфейс, который отпускается(уменьшает счетчик) после всего(в неявной try-finally секции), в том числе - после FreeLibrary(lib)...
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.061 c