Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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.066 c
15-1275924128
bss
2010-06-07 19:22
2010.08.27
Регулярные выражения: как проверить вхождение числа в диапазон


15-1269440695
McSimm
2010-03-24 17:24
2010.08.27
142,10 WMR кто-нибудь переводил ?


2-1270057433
pleasure
2010-03-31 21:43
2010.08.27
Профили меню в БД MSSQL


15-1266214599
Дмитрий С
2010-02-15 09:16
2010.08.27
У вас работает virtual treeview в delphi2010?


3-1242392291
denis24
2009-05-15 16:58
2010.08.27
обрыв канала связи,выключение сервера





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