Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

передача TStream из DLL


Страницы:   1 2

fford ©   (2010-03-09 13:32:00) 

Здравствуйте!
Вот нашел в инете такую статью
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

где грабли? :)


han_malign   (2010-03-09 16:36:00) [1]


> result:=TStreamAdapter.Create(m, soOwned) as IStream;

function GetText(Path,FileName:Pchar; outStream: IStream): HRESULT; stdcall;
...
  Result:= E_UNEXPECTED;
  Stream:=TStreamAdapter.Create(m, soOwned) as IStream;//may raise exception
  Result:= S_OK;
...
TExternStream = class(TStream)
...
   constructor Create( varSource : IStream);


Результат - function GetText(...):IStream - временный экземпляр объекта типа интерфейс, который отпускается(уменьшает счетчик) после всего(в неявной try-finally секции), в том числе - после FreeLibrary(lib)...


fford   (2010-03-09 16:24:00) [2]


> Сергей М. ©   (09.03.10 16:16) [24]


полностью согласен :)


Сергей М.   (2010-03-09 16:16:00) [3]

> ActiveX нужен ибо там описан IStream

Из-да одного интерфейса я бы не стал тащить в проект целый юнит.

Вполне достаточно перетащить оттуда к себе декларации интерфейсов ISequentialStream и IStream (ну и Largeint, если Int64 глаз режет)


fford   (2010-03-09 16:09:00) [4]


> Сергей М. ©   (09.03.10 16:04) [22]

GetName не используется

а GtText не важен можно его закоментировать
т.к. закоментирована строка

//st:=ReadFilesTo(StrPas(Path),StrPas(FileName));

в собственно той функции которая и вызывается из DLL

т.е. этот вызов я просто убрал и создаю TStringList, куда добавляю две строки
создаю поток, копирую туда эти строки
возвращаю интерфейс потока свзяанный с созданным потоком
и удаляю StringList за не надобностью, т.к. его копия уже есть в потоке.

ActiveX нужен
ибо там описан IStream


Сергей М.   (2010-03-09 16:04:00) [5]

GetName в хост приложении используется ?


> GtText in 'GtText.pas';


А где текст юнита GtText ? Что у тебя в нем творится ?


> ActiveX


Это зачем ?


fford   (2010-03-09 15:57:00) [6]

ничего особенного :)
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 15:48:00) [7]


> fford   (09.03.10 15:45) [19]


Приведи полный текст dll ..


fford   (2010-03-09 15:45:00) [8]


> Сергей М. ©   (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;


рез-тат тотже :(


fford   (2010-03-09 15:32:00) [9]


> Игорь Шевченко ©   (09.03.10 15:26) [16]

не спорю
но не полностью

и главное что поток то передается :)
т.е. программа спокойно читает то что сформировала DLL
только вопрос в освобождении памяти
вот тут непонятно


Сергей М.   (2010-03-09 15:27:00) [10]

Ты уверен, что твоя реализация ф-ции ReadFilesTo чиста и непорочна ?


Игорь Шевченко   (2010-03-09 15:26:00) [11]


> нашел статью где написано как очень просто передавать данные
> потока из DLL в программу и наоборот
> соответственно без использования BORLNDMM.DLL


Плохую статью нашел. По ссылке из нее:

"Как известно в Dll нельзя передавать объекты классов, а интерфейсы очень даже можно, при этом идеально сохраняется принцип инкапсуляции класса и объектный подход к разарботке приложений.
"

Это бред


fford   (2010-03-09 15:07:00) [12]


> Ega23 ©   (09.03.10 14:53) [13]

да читал я его и не единожды
:)
только вопрос то не в том
еще раз повторюсь, нашел статью где написано как очень просто передавать данные потока из DLL в программу и наоборот
соответственно без использования BORLNDMM.DLL


Сергей М.   (2010-03-09 15:02:00) [13]


> а его деструкторе интерфейсную ссылку обнуляют


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

Попробуй в классе TExternStream перекрыть деструктор Destroy, чтобы обнилить интерфейсную FSource ссылку явно


Ega23   (2010-03-09 14:53:00) [14]


> > Ты, когда DLL делаешь, комментарий читай в файле проекта
>
> например?


File -> New Project -> DLL.
Там сгенерируется такой большой комментарий, который почему-то все удаляют не читая. А напрасно.


fford   (2010-03-09 14:46:00) [15]

яже писал что ничего не изменял, взял его из статьи :)
вот то что у меня в проекте
:)

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;


Сергей М.   (2010-03-09 14:43:00) [16]

Покажи декларацию своего класса TExternStream и реализацию его конструктора Create ..


fford   (2010-03-09 14:41:00) [17]


> Ты, когда DLL делаешь, комментарий читай в файле проекта

например?


Игорь Шевченко   (2010-03-09 14:36:00) [18]

Ты, когда DLL делаешь, комментарий читай в файле проекта


fford   (2010-03-09 14:32:00) [19]


> Собирать и exe и dll с единым менеджером памяти.

ды вариантов много то  :)
как имнимум просто создавать файл из самой DLL а в программе его открывать

но было интересно попробовать именно с потоками
тем более у автора статьи все очень просто выглядит
а потоки действительно удобная вещь получаются для обмена большими массивами данных между DLL и программой

лучше вот подскажите
как быть с пунктами 4 и 5
т.е. как корректно освободить память из под потока
и DLL
:)


Ega23   (2010-03-09 14:27:00) [20]


> т.е. получается либо на интерфейс остались ссылки, но я
> при вызове деструктора класса обертки вроде обнуляю ссылку,
>  либо программа не может выгружать DLL т.к. с куском памяти
> его связан интерфейс.


Собирать и exe и dll с единым менеджером памяти.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо