Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
SoulStream
Guest
Понадобилось сделать "прослойку" между IStream и IStream. Применений планируется много разных, но в качестве минимального тестирования - пытаюсь засунуть в GDI+.
Лезут ошибки от AV 00300308 до AV 00000000 и AV 00000001... Не мог понять в чём дело, подумал, выкинул весь собственный функционал "прослойки" оставил лишь "базу" - а фик, всё равно падает.

Подскажите пожалуйста, что же ему не так? Я ж уже всё выкинул и сейчас уже просто перенаправляю вызовы, откуда там взяться AV?:
+ Проверка прослойки
unit Unit1;

interface

uses
    System.SysUtils, System.Classes, System.Win.ComObj,
    Vcl.Forms, Vcl.StdCtrls, Vcl.Controls, Vcl.ExtCtrls,
    Winapi.ActiveX, Winapi.ShLwApi,
    Unit2;

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

var Form1: TForm1;

implementation

uses GDIPAPI;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
    Stream: IStream; Wrapper: IStreamWrapper;
    GPSI: GdiplusStartupInput; GPToken: Cardinal; GPPicture: GpImage; GPCanvas: GpGraphics;
begin
GPSI.GdiplusVersion:=1;
GPSI.DebugEventCallback:=Nil;
GPSI.SuppressBackgroundThread:=False;
GPSI.SuppressExternalCodecs:=False;
if (Ok<>GdiplusStartup(GPToken, @GPSI, Nil)) then raise Exception.Create('GdiplusStartup Failed');
OleCheck(SHCreateStreamOnFile('C:\<...>\<...>.jpg', STGM_READ, Stream));
Wrapper:=IStreamWrapper.Create(Stream);
if (Ok<>GdipLoadImageFromStream(Wrapper, GPPicture)) then raise Exception.Create('GdipLoadImageFromStream Failed');
if (Ok<>GdipCreateFromHWND(Handle, GPCanvas)) then raise Exception.Create('GdipCreateFromHWND Failed');
if (Ok<>GdipDrawImage(GPCanvas, GPPicture, 0, 0)) then raise Exception.Create('GdipDrawImage Failed');
GdipDisposeImage(GPPicture);
GdipDeleteGraphics(GPCanvas);
GdiplusShutdown(GPToken);
Wrapper:=nil;
Stream:=nil;
end;

end.
+ Прослойка
unit Unit2;

interface

uses Winapi.Windows, Winapi.ActiveX;

type
    IStreamWrapper = class(TInterfacedObject, IStream)
    private
        OrigStream: IStream;
    public
        constructor Create(Stream: IStream);
        destructor Destroy(); override;
        {$IFDEF FPC} // у Делфи и Лазаруса разное описание IStream
            function Stat(out statstg: TStatStg; grfStatFlag: Longint): HRESULT; stdcall;
            function Seek(dlibMove: LargeUInt; dwOrigin: Longint; out libNewPosition: LargeUInt): HRESULT; stdcall;
            function Read(pv: Pointer; cb: DWORD; pcbRead: PDWORD): HRESULT; stdcall;
            function Write(pv: Pointer; cb: DWORD; pcbWritten: PDWORD): HRESULT; stdcall;
            function SetSize(libNewSize: LargeUInt): HRESULT; stdcall;
            function CopyTo(stm: IStream; cb: LargeUInt; out cbRead: LargeUInt; out cbWritten: LargeUInt): HRESULT; stdcall;
            function Commit(grfCommitFlags: Longint): HRESULT; stdcall;
            function Revert(): HRESULT; stdcall;
            function LockRegion(libOffset: LargeUInt; cb: LargeUInt; dwLockType: Longint): HRESULT; stdcall;
            function UnlockRegion(libOffset: LargeUInt; cb: LargeUInt; dwLockType: Longint): HRESULT; stdcall;
            function Clone(out stm: IStream): HRESULT; stdcall;
        {$ELSE}
            function Stat(out statstg: TStatStg; grfStatFlag: Cardinal): HRESULT; stdcall;
            function Seek(dlibMove: Int64; dwOrigin: Cardinal; out libNewPosition: UInt64): HRESULT; stdcall;
            function Read(pv: Pointer; cb: Cardinal; pcbRead: PFixedUInt): HRESULT; stdcall;
            function Write(pv: Pointer; cb: Cardinal; pcbWritten: PFixedUInt): HRESULT; stdcall;
            function SetSize(libNewSize: UInt64): HRESULT; stdcall;
            function CopyTo(stm: IStream; cb: UInt64; out cbRead: UInt64; out cbWritten: UInt64): HRESULT; stdcall;
            function Commit(grfCommitFlags: Cardinal): HRESULT; stdcall;
            function Revert(): HRESULT; stdcall;
            function LockRegion(libOffset: UInt64; cb: UInt64; dwLockType: Cardinal): HRESULT; stdcall;
            function UnlockRegion(libOffset: UInt64; cb: UInt64; dwLockType: Cardinal): HRESULT; stdcall;
            function Clone(out stm: IStream): HRESULT; stdcall;
        {$ENDIF}
    end;

implementation

constructor IStreamWrapper.Create;
begin
OrigStream:=Stream;
end;

destructor IStreamWrapper.Destroy;
begin
OrigStream:=nil;
inherited;
end;

function IStreamWrapper.Stat;
begin
Result:=OrigStream.Stat(statstg, grfStatFlag);
end;

function IStreamWrapper.Seek;
begin
Result:=OrigStream.Seek(dlibMove, dwOrigin, libNewPosition);
end;

function IStreamWrapper.Read;
begin
Result:=OrigStream.Read(pv, cb, pcbRead);
end;

function IStreamWrapper.Write;
begin
Result:=STG_E_UNIMPLEMENTEDFUNCTION;
end;

function IStreamWrapper.SetSize;
begin
Result:=STG_E_UNIMPLEMENTEDFUNCTION;
end;

function IStreamWrapper.CopyTo;
begin
Result:=STG_E_UNIMPLEMENTEDFUNCTION;
end;

function IStreamWrapper.Commit;
begin
Result:=STG_E_UNIMPLEMENTEDFUNCTION;
end;

function IStreamWrapper.Revert;
begin
Result:=STG_E_UNIMPLEMENTEDFUNCTION;
end;

function IStreamWrapper.LockRegion;
begin
Result:=STG_E_UNIMPLEMENTEDFUNCTION;
end;

function IStreamWrapper.UnlockRegion;
begin
Result:=STG_E_UNIMPLEMENTEDFUNCTION;
end;

function IStreamWrapper.Clone;
begin
Result:=STG_E_UNIMPLEMENTEDFUNCTION;
end;

end.

Кстати зачем они задекларировали кучу параметров как "out"? Туда же передаётся указатель, и довольно часто передаётся NULL.
Ни я не могу нормально NULL передать, ни нормально проверить что мне передали NULL... Нафига вот NULLABLE параметр декларировать через "out"?
3 июл 18, 11:10    [21538638]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
SoulStream
Понадобилось сделать "прослойку" между IStream и IStream.
Зачем?
SoulStream
. Нафига вот NULLABLE параметр декларировать через "out"?
Это вопрос к эмбаркадере, которая так проимпортила заголовки
SoulStream
Ни я не могу нормально NULL передать,
Pointer(nil)^

SoulStream
ни нормально проверить что мне передали NULL
if @InVar = nil then
3 июл 18, 12:41    [21538990]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
SoulStream
Guest
Получаем IStream от какой-нибудь библиотеки/объекта и нам надо передать информацию из этого IStream в другую библиотеку/объект (тоже принимающие IStream), но с некоторыми модификациями.
И ещё столкнулись с ситуациями, что данный нам IStream может не иметь реализаций для CopyTo/Clone и прочих - возвращает STG_E_UNIMPLEMENTEDFUNCTION и всё тут.

Но какая разница зачем, я же сейчас убрал все свои модификации - почему не рабоатет даже простое перенаправление?? Наверное это я не учёл какой-то нюанс, но какой? Кто-то может направить?

+ to _Vasilisk_

Не только к Эмбаркадере, Лазарус/FPC туда же, даже JEDI. Понятно что вопрос к ним, а я просто возмущаюсь))
Интересно что форумчане думают на этот счёт. Ну и вдруг разработчики прочитают меня и пересморят.
_Vasilisk_
[src delphi]if @InVar = nil then
Сейчас так и делаю, но ИМХО это выглядит коряво.
_Vasilisk_
Pointer(nil)^
Не-а. Во-первых выглядит тоже хреново. Во-вторых так как раз не работает:
Delphi
E2033 Types of actual and formal var parameters must be identical
Lazarus
Error: Call by var for arg no. 3 has to match exactly: Got "untyped" expected "...."
Приходится вот так:
PUInt64(nil)^
или так:
PLargeUInt(nil)^
...или ещё как... И в разных местах приходится писать по-разному... Выглядит ваще коряво.
И вообще есть мнение что если в коде используется символ ^ то код скорее всего "не очень хороший". В описании типа данных символ ^ - это нормально. Но не в самом исполняемом коде.
3 июл 18, 13:47    [21539233]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
SoulStream
Во-вторых так как раз не работает:
Я имел в виду, что вместо Pointer нужно подставить указатель на тот тип, который требуется
SoulStream
Наверное это я не учёл какой-то нюанс, но какой?
Только, что заметил, что вы сделали. Запомните НИКОГДА не смешивайте работу с классовыми и интерфейсными объектами. Если у вас есть объект, то вы работаете с ним или только как с классом, или только как с интерфейсом (смешивать можно, но нужно четко понимать, что вы делаете и что при этом происходит).

Вот так все будет работать
var
  Stream: IStream; 
  Wrapper: IStream;
  GPSI: GdiplusStartupInput; GPToken: Cardinal; GPPicture: GpImage; GPCanvas: GpGraphics;
begin


И еще, если не хотите, чтобы вас били, а хотели бы, чтобы вас понимали - придерживайтесь стандартных правил именования. Имена классов начинаются с T, а интерфейсов с I. Так, что в срочном порядке переименуйте ваш класс в
TStreamWrapper = class(TInterfacedObject, IStream)
3 июл 18, 14:17    [21539348]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
ziv-2014
Member

Откуда:
Сообщений: 111
SoulStream,
У тебя OrigStream становится nil. Ты где-то либо стек портишь. У тебя обнуляется Wrapper, вызывается конструктор, с муссором по RefCount, а после вызываются операции с интерфейсом, которые приводят к AV.
3 июл 18, 14:24    [21539377]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
ziv-2014
У тебя OrigStream становится nil. Ты где-то либо стек портишь.
У него после первого же
SoulStream
if (Ok<>GdipLoadImageFromStream(Wrapper, GPPicture))
    then raise Exception.Create('GdipLoadImageFromStream Failed');
уничтожается Wrapper, потому, что это у него объектная ссылка
3 июл 18, 14:28    [21539393]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
ziv-2014
Member

Откуда:
Сообщений: 111
_Vasilisk_,
Ага заметил, так не стоит делать, из-за этого вся боль :)
3 июл 18, 14:33    [21539420]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
SoulStream
Guest
У тебя OrigStream становится nil.
ну... Я ставил проверку на Assigned, она не срабатывала.
после первого же
Не после первого же)))
Мне надоело тыкать F8 и я прикрутил банальное логирование в TMemo: внутри GdipLoadImageFromStream() начинается работа с IStream и успевало вызвать методы аж 8 раз - ток потом вылетало.
А вот до сравнения с "Ok" не доходило даже. Теперь он делает 20 вызовов и завершается успешно. Спасибо вам огромное!
4 июл 18, 06:13    [21541160]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 3059
SoulStream,

что бы все методы вручную не проксировать про Implements погугли

PS: только с XE3
4 июл 18, 11:35    [21541951]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
kealon(Ruslan)
PS: только с XE3
В 2006 уже работало.

Но ему нужно именно, что переопределить методы
4 июл 18, 12:14    [21542097]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
SoulStream
Не после первого же)))
То, что память сама не затиралась после первого вызова - чистая случайность. Деструктор StreamWrapper вызывался сразу же
4 июл 18, 12:16    [21542106]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 3059
_Vasilisk_
kealon(Ruslan)
PS: только с XE3
В 2006 уже работало.

Но ему нужно именно, что переопределить методы

правильно оно работает только с XE3, где-то была ветка с разбором
ему там пару методов переопределить, а не все
4 июл 18, 12:34    [21542176]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
kealon(Ruslan)
где-то была ветка с разбором
Моя это ветка была
4 июл 18, 15:38    [21543031]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 3059
_Vasilisk_,

ну тогда тем более должен знать, что оно не работает нормально
4 июл 18, 15:56    [21543099]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
SoulStream
Guest
Про чего погуглить? По одному слову как-то не особо выходит. И я так и не понял - "работает" или "не работает"?))


Делаю примерно так:
var Wrapper: IStream;
...
Wrapper:=TStreamWrapper.Create(Stream);
...
TStreamWrapper(Wrapper).SomeFieldOrProperty:= ...
В Делфи работает, а вот в Лазарусе не работает. Компилируется с warning'ом и просто не фурычит, пришлось переделать так:
var Wrapper: IStream;
...
Wrapper:=TStreamWrapper.Create(Stream);
...
(Wrapper as TStreamWrapper).SomeFieldOrProperty:= ...
И так уже работает и там и там. Кто-то сможет пояснить почему..?
8 июл 18, 05:11    [21553243]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
SoulStream
Кто-то сможет пояснить почему..?
Вам же говорили не смешивать работу с классами и интерфейсами.

Вот этот код
SoulStream
var Wrapper: IStream;
...
Wrapper:=TStreamWrapper.Create(Stream);
эквивалентен такому
var
  WrapperObj: TStreamWrapper;
  Wrapper: IStream;
...
WrapperObj:=TStreamWrapper.Create(Stream);
if not WrapperObj.GetInterface(IStream, Wrapper) then
  raise Exception.Create('Interface not supported');
по умолчанию WrapperObj.GetInterface возвращает Self. Но это поведение можно легко изменить. Вот этот код
SoulStream
TStreamWrapper(Wrapper)
говорит: "я знаю, что Wrapper это объект класса TStreamWrapper. Компилятор, верь мне". Далее, если вы не угадали, что это тот объект, то все будет работать. Если не угадали, то получите маловразумительные исключения в произвольных местах кода. Delphi вам верит, а Лазарус выражает сомнения.

Вот этот код
SoulStream
(Wrapper as TStreamWrapper)
эквивалентен такому
if not Wrapper is TStreamWrapper then
  raise Exception.Create('Invalid class cast');
TStreamWrapper(Wrapper)....


Т.е. оба варианта плохи. Что делать? Если вам у IStream нужны дополнительные методы/свойства, то нужно поступать так же, как с классами - писать наследника

IStreamWrapper = interface(IStream)
  ['{..........}']  // Тут GUID для генерации нажать Ctrl + Shift + G
  // Methods
  // Properties
  property SomeProperty ....
end;

TStreamWrapper = class(TInterfacedObject, IStream, IStreamWrapper)
  .............
end;

var Wrapper: IStreamWrapper;
...
Wrapper:=TStreamWrapper.Create(Stream);
...
Wrapper.SomeFieldOrProperty:= ...
if (Ok <> GdipLoadImageFromStream(Wrapper, GPPicture)) then
  raise Exception.Create('GdipLoadImageFromStream Failed');
8 июл 18, 10:26    [21553384]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
SoulStream
Guest
+ Lazarus
Если не угадали ...
Как ж мне не угадать - я же сам только что создал свой класс. :) Это точно он.
Но Лазарус говорит:
Unit2.pas(Y,X) Warning: Class types "IStream" and "TStreamWrapper" are not related
И по факту как бы просто не выполняет "property SomeProperty write FField". При этом Делфи выполняет корректно.

ну... Просто создавал-то я класс, только ссылка на него интерфейсная... не?
Ясно, спасибо большое...

kealon(Ruslan)
что бы все методы вручную не проксировать про Implements погугли
...
где-то была ветка с разбором
И всё же про что это? Какая ветка?
8 июл 18, 14:16    [21553824]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
SoulStream
Guest
Но а если мне нужны ещё и поля? Там, Int64 например, Cardinal, WideString? Интерфейс же мне не позволяет поля.
То есть я лишён возможности делать "property SomeProperty read/write FField", а придётся переписывать исключительно в виде объявления методов get/set во втором интерфейсе, а потом ещё и реализовывать их же уже в TStreamWrapper? :(


гм... А что если я буду просто хранить обе ссылки?:
var
  WrapperObject: TStreamWrapper;
  WrapperInterface: IStream;
...
WrapperObject:=TStreamWrapper.Create(Stream);
WrapperInterface:=WrapperObject;
...
WrapperObject.SomeProperty:= ...
...
if (Ok<>GdipLoadImageFromStream(WrapperInterface, GPPicture)) then raise Exception.Create('GdipLoadImageFromStream Failed');
...
WrapperInterface:=nil;
Это будет чем-то совсем плохо?
8 июл 18, 14:20    [21553836]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
SoulStream
Но а если мне нужны ещё и поля?
Поля вообще в любом классе должны объявляться как strict private. И иметь доступ только из класса. Нужен доступ снаружи - объявляйте свойство
SoulStream
придётся переписывать исключительно в виде объявления методов get/set во втором интерфейсе, а потом ещё и реализовывать их же уже в TStreamWrapper? :(
И в чем проблема?
SoulStream
А что если я буду просто хранить обе ссылки?:
когда интерфейсная ссылка обнулит счетчик ссылок - объект уничтожится. Вы на это наступили в самом первом посту.

Хорошо, вот вариант для ленивых
TStreamWrapper = class;

IStreamWrapper = interface(IStream)
  ['{..........}']  // Тут GUID для генерации нажать Ctrl + Shift + G
  function GetObjectImpl: TStreamWrapper;
  property ObjectImpl: TStreamWrapper read GetObjImpl;
end;

TStreamWrapper = class(TInterfacedObject, IStream, IStreamWrapper)
  .............
  function GetObjectImpl: TStreamWrapper;
end;

function TStreamWrapper.GetObjectImpl: TStreamWrapper;
begin
  Result := Self;
end;

var Wrapper: IStreamWrapper;
...
Wrapper:=TStreamWrapper.Create(Stream);
...
Wrapper.ObjectImpl.SomeFieldOrProperty:= ...

Этот вариант кривой до безобразия, но, по крайней мере, лучше чем хранение двух ссылок. Ну и при вызове метод GetObjectImpl из другой dll могут возникнуть проблемы. Т.е., по сути, это те же разложенные грабли. Правильный наследник самое верное решение
8 июл 18, 15:09    [21553910]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
SoulStream
Как ж мне не угадать - я же сам только что создал свой класс. :)
Вы создали объект класса и запросили у него интерфейсную ссылку. Делфи вернула вам тот же указатель, Лазарус - другой
SoulStream
И всё же про что это? Какая ветка?
http://www.sql.ru/forum/1165959/izmenilsya-sposob-vyzova-ekzemplyar-klassa-dlya-queryinterface
8 июл 18, 15:14    [21553916]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
SoulStream
Guest
_Vasilisk_
когда интерфейсная ссылка обнулит счетчик ссылок - объект уничтожится.
Это-то я уже понял, но если я буду хранить обе - то полагаю объект сам не обнулится, пока у меня всё ещё хранится интерфейсная?
Это объектная перестанет быть валидной, когда я обнилю интерфейсную - но я же точно знаю, когда я буду это делать.


Впрочем, я подумал и пришёл к мысли - а так ли нужен мне вообще property, почему просто не пользоваться методоми set/get (тем более что их всё равно не сделать private)?

Чем-то будет отличаться это:
    IStreamWrapper = Interface(IStream)
        ['...']
        ...
    end;
    TStreamWrapper = Class(TInterfacedObject, IStream, IStreamWrapper)
        ...
от вот этого?:
    IStreamWrapper = Interface(IStream)
        ['...']
        ...
    end;
    TStreamWrapper = Class(TInterfacedObject, IStreamWrapper)
        ...

И ещё тут нашёл/прочитал - советуют всегда использовать safecall, и аргументируют мощно, надо подумать... С:
8 июл 18, 23:17    [21554622]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
SoulStream
Чем-то будет отличаться это:
Тем, что QueryInterface(IStream) работать не будет. Попробуйте такой код с обоими вариантами

var
  Wrapper: IStreamWrapper;
  Strm: IStream;
  Intf: IInterface;
begin
  Wrapper := TStreamWrapper.Create(...);
  Strm := Wrapper;
  Intf := Wrapper;
  OleCheck(Intf.QueryInterface(IStream, Strm));
end;

SoulStream
советуют всегда использовать safecall
Это для COM. Там правила жестче. Для внутренней реализации это не обязательно. И будет немного медленнее.
9 июл 18, 14:28    [21556371]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10390
SoulStream
Это объектная перестанет быть валидной, когда я обнилю интерфейсную - но я же точно знаю, когда я буду это делать.
Сейчас будете знать. А через месяц? Если уже делать гибрид, то не храните объектную ссылку вообще. А каждый раз запрашивайте у интерфейса. Оно безопаснее
SoulStream
а так ли нужен мне вообще property, почему просто не пользоваться методоми set/get
А какая разница? Тем более, что property можно не объявлять в классе. Достаточно их объявить в интерфейсе
9 июл 18, 14:31    [21556399]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 3059
SoulStream
kealon(Ruslan)
что бы все методы вручную не проксировать про Implements погугли
...
где-то была ветка с разбором
И всё же про что это? Какая ветка?
17876455
9 июл 18, 19:42    [21557540]     Ответить | Цитировать Сообщить модератору
 Re: Не выходит сделать прослойку между IStream и IStream: Access violation.  [new]
SoulStream
Guest
Спасибо огромное всем! Вроде получилось, работает как задумано, ведётся активное тестирование!
11 июл 18, 21:57    [21564120]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить