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

Вниз

Работа с интерфейсами...   Найти похожие ветки 

 
kull ©   (2003-08-06 10:04) [0]

Привет народ!
У меня небольшая проблемма, вот пример кода:

unit example;

interface

type
I1 = interface (IUnknown)
["{884D4F64-C7F2-11D7-99BE-444553540000}"]
end;

T1 = class (TObject, I1)
public
( const I: I1)
Привет народ!
У меня небольшая проблемма, вот пример кода:

unit example;

interface

type
I1 = interface (IUnknown)
["{884D4F64-C7F2-11D7-99BE-444553540000}"]
end;

T1 = class (TObject, I1)
public
constructor Create;
end;


procedure InitData(const I: I1);

implementation

procedure InitData(const I: I1);
begin
{do nothing}
end;

constructor T1.Create;
begin
inherited Create;
InitData(self as I1);
end;


end.


Так вот, в конструкторе T1.Create при выходе из функции InitData, счетчик ссылок уменьшается на 1, и становится = 0. Естественно сразу же вызывается деструктор T1.Destroy.

Как предлагаете решить эту проблемму?


 
icWasya ©   (2003-08-06 10:27) [1]

вариант первый

вместо
T1 = class (TObject, I1)

писать

T1 = class ( TInterfacedObject, I1)

и
вместо

var O:T1;
..
T1:=T1.Create;


писать

var O: I1;

..
I1 := T1.Create as I1;


и никогда не работать о объектами, а только с интерфейсами

вариант второй
ежели автоманический подсчёт ссылок - вещь слишком сложная, то можно попытаться её отключить


type
TNonInterfacedObject = Class(TInterfacedObject)
protected
function _AddRef: Integer; stdcall;
( TNonInterfacedObject, I1)
вариант первый

вместо
T1 = class (TObject, I1)

писать

T1 = class ( TInterfacedObject, I1)

и
вместо

var O:T1;
..
T1:=T1.Create;


писать

var O: I1;

..
I1 := T1.Create as I1;


и никогда не работать о объектами, а только с интерфейсами

вариант второй
ежели автоманический подсчёт ссылок - вещь слишком сложная, то можно попытаться её отключить


type
TNonInterfacedObject = Class(TInterfacedObject)
protected
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;

T1 = class ( TNonInterfacedObject, I1)


function TNonInterfacedObject._AddRef:Integer;
begin
Result:=1;
end;
function TNonInterfacedObject._Release:Integer;
begin
Result:=1;
end;

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


 
kull ©   (2003-08-06 13:41) [2]


> T1 = class (TInterfacedObject, I1)

Да, да... Так у меня и объявлено на самом деле. Просто я пример от руки набросал по скорому и не компилял...


> var O:T1;
> ..
> T1:=T1.Create;

Что-то подобного я у себя не нашел в коде... И в каком месте я работаю с объектом?
Я вовсе не смешиваю работу с объектами и интерфейсами. Просто как еще объекту передать ссылку на свой интерфейс?

Второй вариант: хотелось бы все же по возможности не заботится самому о подсчете ссылок, а предоставить это Delphi.
Result:=1 вообще подозрительно выглядит. Как объект уничтожаться то будет, методом Free? А как же работа только с интерфейсами, а не с объектами?

Ну а... ежели решение этой задачи - вещь слишком сложная, то можно попытаться добавить еще один метод к интерфейсу I1 и в нем уже вызывать InitData, ну типа:

type
I1 = interface (IUnknown)
["{884D4F64-C7F2-11D7-99BE-444553540000}"]
procedure Init;
end;

T1 = class (TInterfacedObject, I1)
private
procedure Init;
public
( const I: I1)

> T1 = class (TInterfacedObject, I1)

Да, да... Так у меня и объявлено на самом деле. Просто я пример от руки набросал по скорому и не компилял...


> var O:T1;
> ..
> T1:=T1.Create;

Что-то подобного я у себя не нашел в коде... И в каком месте я работаю с объектом?
Я вовсе не смешиваю работу с объектами и интерфейсами. Просто как еще объекту передать ссылку на свой интерфейс?

Второй вариант: хотелось бы все же по возможности не заботится самому о подсчете ссылок, а предоставить это Delphi.
Result:=1 вообще подозрительно выглядит. Как объект уничтожаться то будет, методом Free? А как же работа только с интерфейсами, а не с объектами?

Ну а... ежели решение этой задачи - вещь слишком сложная, то можно попытаться добавить еще один метод к интерфейсу I1 и в нем уже вызывать InitData, ну типа:

type
I1 = interface (IUnknown)
["{884D4F64-C7F2-11D7-99BE-444553540000}"]
procedure Init;
end;

T1 = class (TInterfacedObject, I1)
private
procedure Init;
public
constructor Create;
end;

procedure InitData(const I: I1);

implementation

procedure InitData(const I: I1);
begin
{do nothing}
end;

procedure T1.Init;
begin
InitData(self as I1);
end;

...
procedure F;
begin
I1 := T1.Create;
I1.Init;
end;

...


Но все таки, можно ли как-то это сделать в конструкторе?


 
icWasya ©   (2003-08-06 13:58) [3]

попробуй так

constructor T1.Create;
var I:I1;
begin
inherited Create;
if GetInterface(I1,I) then InitData(I); (*в этом случае не будут вызываться AddRef/Release*)
end;



 
reonid ©   (2003-08-06 14:01) [4]

Похоже, придётся в конструкторе вручную увеличить счётчик.
И при этом переписать AfterConstruction, чтобы в нём
счётчик не увеличивался.


 
reonid ©   (2003-08-06 14:05) [5]

icWasya © (06.08.03 13:58)

>этом случае не будут вызываться AddRef/Release
Это с какой стати?

Тут проблема в том, что в конструкторе счётчик ещё равен 0 -
он увеличивается до 1 только в AfterConstruction.


 
Serginio   (2003-08-06 14:24) [6]

У тебя проблема заключается в том, что вызываешь из конструктора и у него до передачи данных в переменную не вызывается _Addref и счетчик ссылок =0, а при _Release проверяется это счетчик и если он =0 вызывается Destroy.
procedure T1.Create;
Var Value:I1;
Int:Integer;
begin
Value:self as I1;
Value._Addref;
InitData(Value);
{ Value._Addref;
Int:=Value._Release;
If Int>2 Then
( Value) У тебя проблема заключается в том, что вызываешь из конструктора и у него до передачи данных в переменную не вызывается _Addref и счетчик ссылок =0, а при _Release проверяется это счетчик и если он =0 вызывается Destroy.
procedure T1.Create;
Var Value:I1;
Int:Integer;
begin
Value:self as I1;
Value._Addref;
InitData(Value);
{ Value._Addref;
Int:=Value._Release;
If Int>2 Then
Value._Release;}
end;
Тогда после присваивания переменной нужно вызывать _Release
V:=T1.Create;
V._Release;

Или смотри реализацию _Release и устанавливай счетчик в 0

Напрмер
procedure T1.Create;
Var Value:I1;
Int:Integer;
begin
Value:self as I1;
Value._Addref;
InitData(Value);
Value:=nil;
RefCount:=0;
end;
Но
Вообщето из конструктора делать вызовы чревато.




 
reonid ©   (2003-08-06 14:35) [7]

я не был прав, стормозил.


 
icWasya ©   (2003-08-06 14:40) [8]

У меня вот это работает и не разваливается

unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
AA:TObject;
{ Public declarations }
end;

var
Form1: TForm1;

implementation
{$R *.DFM}

procedure AddS(const S:String);
begin
Form1.ListBox1.Items.Add(S);
end;

type
I1 = interface (IUnknown)
["{884D4F64-C7F2-11D7-99BE-444553540000}"]
function GetX: Integer;
procedure SetX(Value: Integer);
property X:Integer read GetX write SetX;
end;

T1 = class (TInterfacedObject, I1)
FX:Integer;
private
function GetX: Integer;
procedure SetX(Value: Integer);
public
constructor Create;
destructor Destroy;override;
end;



procedure InitData(I: I1);
begin
AddS("InitData Begin");
I.X:=100;
AddS("InitData End");
end;

constructor T1.Create;
begin
inherited Create;
AddS("constructor T1.Create;");
AddS("Before InitData");

InitData(Self as I1);
AddS("After InitData");

end;


procedure TForm1.Button1Click(Sender: TObject);
var I:I1;
begin
ListBox1.Items.Clear;
AddS("Before I:=T1.Create;");
I:=T1.Create;
AddS("After I:=T1.Create;");


AddS("Before Button1.Caption:=IntToStr(I.X);");
( I.X)
У меня вот это работает и не разваливается

unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
AA:TObject;
{ Public declarations }
end;

var
Form1: TForm1;

implementation
{$R *.DFM}

procedure AddS(const S:String);
begin
Form1.ListBox1.Items.Add(S);
end;

type
I1 = interface (IUnknown)
["{884D4F64-C7F2-11D7-99BE-444553540000}"]
function GetX: Integer;
procedure SetX(Value: Integer);
property X:Integer read GetX write SetX;
end;

T1 = class (TInterfacedObject, I1)
FX:Integer;
private
function GetX: Integer;
procedure SetX(Value: Integer);
public
constructor Create;
destructor Destroy;override;
end;



procedure InitData(I: I1);
begin
AddS("InitData Begin");
I.X:=100;
AddS("InitData End");
end;

constructor T1.Create;
begin
inherited Create;
AddS("constructor T1.Create;");
AddS("Before InitData");

InitData(Self as I1);
AddS("After InitData");

end;


procedure TForm1.Button1Click(Sender: TObject);
var I:I1;
begin
ListBox1.Items.Clear;
AddS("Before I:=T1.Create;");
I:=T1.Create;
AddS("After I:=T1.Create;");


AddS("Before Button1.Caption:=IntToStr(I.X);");
Button1.Caption:=IntToStr(I.X);
AddS("After Button1.Caption:=IntToStr(I.X);");

AddS("Before I:=Nil;");
I:=Nil;
AddS("After I:=Nil;");

end;

destructor T1.Destroy;
begin
inherited;
AddS("destructor T1.Destroy;");

end;

Function T1.GetX:Integer;
begin
Result:=FX;
AddS("Function T1.GetX:Integer;");
end;

procedure T1.SetX(Value: Integer);
begin
FX:=Value;
AddS("procedure T1.SetX(Value: Integer);");
end;

end.

и

object Form1: TForm1
Left = 229
Top = 137
Width = 501
Height = 380
Caption = "Form1"
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = "MS Sans Serif"
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 64
Top = 112
Width = 75
Height = 25
Caption = "Button1"
TabOrder = 0
OnClick = Button1Click
end
object ListBox1: TListBox
Left = 168
Top = 32
Width = 281
Height = 281
ItemHeight = 13
TabOrder = 1
end
end



 
vuk ©   (2003-08-06 15:22) [9]

to Kull:
Не понятно, откуда возникает Ваша проблема. Дело в том, что при входе в конструктор счетчик ссылок равен 1, а не 0.


 
Набережных С. ©   (2003-08-06 21:23) [10]

>vuk © (06.08.03 15:22)

Это для TInterfacedObject. Для TComObject ставится в одном из конструкторов. А тут вообще бред какой-то. Где реализация методов IUnknown? Где счетчик ссылок? В общем, вопрос ни о чем.


 
vuk ©   (2003-08-06 21:48) [11]

to Набережных С.:
>Это для TInterfacedObject.
См. kull © (06.08.03 13:41). Там в самом начале сообщения написано, что на самом деле используется TInterfacedObject.


 
Набережных С. ©   (2003-08-06 21:57) [12]

>vuk © (06.08.03 21:48)
Да, верно, проглядел


 
kull ©   (2003-08-07 13:26) [13]

Все оказалось еще интереснее...
Ниже указанный код в D7 работает на ура и выдает сообщения в следующем порядке:

"Init"
"Init"

А в D4:

"Init"
"Destroy"
"Fuck!"

Затем с грохотом валится...

Причем счетчик ссылок в Create в D4 равен 0, а в D7 равен 1.

unit Unit1;

interface

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

type
I1 = interface
["{DF0D5AA0-C867-11D7-99BE-D97BA81E407F}"]
end;

I2 = interface
procedure Init(const I: I1);
end;

T1 = class(TInterfacedObject, I1)
private
F: I2;
public
constructor Create;
destructor Destroy; override;
end;

T2 = class(TInterfacedObject, I2)
private
procedure Init(const I: I1);
end;

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
F: I1;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
F := T1.Create;
end;

{ T1 }

constructor T1.Create;
begin
inherited;
F := T2.Create;
F.Init(self as I1);
try
F.Init(self as I1);
except
( "Fuck!")
Все оказалось еще интереснее...
Ниже указанный код в D7 работает на ура и выдает сообщения в следующем порядке:

"Init"
"Init"

А в D4:

"Init"
"Destroy"
"Fuck!"

Затем с грохотом валится...

Причем счетчик ссылок в Create в D4 равен 0, а в D7 равен 1.

unit Unit1;

interface

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

type
I1 = interface
["{DF0D5AA0-C867-11D7-99BE-D97BA81E407F}"]
end;

I2 = interface
procedure Init(const I: I1);
end;

T1 = class(TInterfacedObject, I1)
private
F: I2;
public
constructor Create;
destructor Destroy; override;
end;

T2 = class(TInterfacedObject, I2)
private
procedure Init(const I: I1);
end;

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
F: I1;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
F := T1.Create;
end;

{ T1 }

constructor T1.Create;
begin
inherited;
F := T2.Create;
F.Init(self as I1);
try
F.Init(self as I1);
except
ShowMessage("Fuck!");
end;
end;

destructor T1.Destroy;
begin
ShowMessage("Destroy");
inherited;
end;

{ T2 }

procedure T2.Init(const I: I1);
begin
ShowMessage("Init");
end;


end.


так что у там, где этот код работает наверняка стоит не D4.
Печально но мне нужно именно для Delphi4... :(


 
vuk ©   (2003-08-07 13:37) [14]

Ну так создайте наследника от TInterfacedObject, перекройте пару методов (NewInstance и AfterConstruction), реализуйте то, что сделано в старших версиях Delphi и далее классы наследуйте от него.


 
kull ©   (2003-08-07 13:42) [15]

Ладно, прийдется что-нибуть придумать.


 
vuk ©   (2003-08-07 13:44) [16]

Кстати о птичках. Не помню, как в D4, но в D5 и выше счетчик ссылок объявлен как protected, следовательно он доступен наследникам непосредственно без всяких извращений и Вы можете изменять его значение вручную.



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

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

Наверх




Память: 0.53 MB
Время: 0.013 c
4-68598
Alexander666
2003-06-18 22:30
2003.08.21
Завершение процесса


3-68237
Romann
2003-07-26 09:57
2003.08.21
Таблицы FoxPro


14-68458
Johnny Smith
2003-08-04 15:49
2003.08.21
Девушки-некрофилки. Миф или реальность? Разрешать или нет?


14-68550
edik
2003-08-02 16:38
2003.08.21
Где взять документацию


6-68431
FireMan_Alexey
2003-06-05 15:38
2003.08.21
TSocketServer! Возможно ли сделать именно так?