Jump to content
HaSo4

Same GUID used in interfaces, is there any purpose for this?

Recommended Posts

Good day,

I noticed that under D11.3, at

Data.Bind.Components.pas,

that the GUID is the same.
Usually I would consider that as an error, but with the inherited interfaces I'm unsure, if there is probably a deeper purpose or hack behind:

  IBindCompFactoryContext = interface
    ['{E0FB570F-2EF0-44C7-BD19-F4F8ACAE2294}']
    function GetDesigner: IInterface;
    function GetControlComponent: TComponent;
    function GetOwner: TComponent;
    function GetBindingsList: TCustomBindingsList;
    property BindingsList: TCustomBindingsList read GetBindingsList;
    property Owner: TComponent read GetOwner;
    property ControlComponent: TComponent read GetControlComponent;
    property Designer: IInterface read GetDesigner;
  end;

  IBindCompFactoryExecuteContext = interface(IBindCompFactoryContext)
    ['{E0FB570F-2EF0-44C7-BD19-F4F8ACAE2294}']
    function UniqueName(const ABaseName: string): string;
    procedure BindCompCreated(AComponent: TComponent);
  end;

 

Please give me some more insights, if there were any.

 

Share this post


Link to post

You must use GUIDs when there is a need to use RTTI "as" and "is". Like you told, each interface should have a unique GUID, but I have already see that.

 

Start from here: https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Object_Interfaces_(Delphi)

 

(may be the link is wrong ... wiki is down at the time of writing)

 

P.S.: You can read also these books (with examples)

- Hodges Nick - Coding in Delphi (year 2013)

- Hodges Nick - More Coding in Delphi  (year 2015)

 

I don't know if there are something that can help you ...

 

Edited by DelphiUdIT

Share this post


Link to post

Since these interfaces are not identical they should have different GUIDs. If only one of them (IBindCompFactoryExecuteContext) is ever instantiated, only this one should have a GUID.

 

So yes, that's a bug. Probably caused by copy and paste, as most of these errors.

Edited by dummzeuch
  • Like 2

Share this post


Link to post

Thank you, then I'm reassured that my world of interface GUIDs is still intact.

Share this post


Link to post
14 hours ago, DelphiUdIT said:

You must use GUIDs when there is a need to use RTTI "as" and "is". Like you told, each interface should have a unique GUID, but I have already see that.

 

Start from here: https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Object_Interfaces_(Delphi)

 

(may be the link is wrong ... wiki is down at the time of writing)

 

P.S.: You can read also these books (with examples)

- Hodges Nick - Coding in Delphi (year 2013)

- Hodges Nick - More Coding in Delphi  (year 2015)

 

I don't know if there are something that can help you ...

 

I think the asker knows what GUIDs are used for. However the question is whether the use of the same GUID for two distinct interfaces is a bug or not. 

Share this post


Link to post
9 minutes ago, David Heffernan said:

I think the asker knows what GUIDs are used for. However the question is whether the use of the same GUID for two distinct interfaces is a bug or not. 

I agree with you, I just wanted to point out some sources on where to possibly look for further useful information on the topic.

I've already seen double GUIDs in interfaces in COM environments, and they worked correctly (or at least I never detected problems), but I never looked into them further.

Share this post


Link to post
3 hours ago, DelphiUdIT said:

or at least I never detected problems

I'm pretty sure they will show problems, when both interfaces need's to be accessed via Rtti both.
Perhaps it is just a lucky coincidence that both interfaces have not yet been used via Rtti.

 

In any case, this is not an acceptable condition to me, and it's clear that it's not a clever hack.
Thanks for your help to clarify this topic anyway.

Share this post


Link to post

RTTI does have nothing to do with it but TObject.GetInterfaceEntry - try the following code:

 

type
  IFoo = interface
    ['{5DEC09C5-FADC-46A5-814F-9ED91259A37F}']
    function GetFooName: string;
  end;

  IBar = interface
    ['{5DEC09C5-FADC-46A5-814F-9ED91259A37F}']
    function GetBarName: string;
  end;

  TFooBar = class(TInterfacedObject, IFoo, IBar)
    function GetFooName: string;
    function GetBarName: string;
  end;

function TFooBar.GetFooName: string;
begin
  Result := 'Foo';
end;

function TFooBar.GetBarName: string;
begin
  Result := 'Bar';
end;

var
  i: IInterface;
begin
  i := TFooBar.Create;
  Writeln((i as IFoo).GetFooName);
  Writeln((i as IBar).GetBarName);
end.

The interesting thing with those two interfaces in the RTL is that coincidentally they will not cause any harm because of how they are implemented and related to each other - the one inherits from the other and they are also implemented by classes that inherit from each other.

Edited by Stefan Glienke
  • Like 1

Share this post


Link to post
6 minutes ago, Stefan Glienke said:

RTTI does have nothing to do with it but TObject.GetInterfaceEntry - try the following code:

Great example !

and i want to expand on this a little

  System.SysUtils;

  type
  IFoo = interface
    ['{5DEC09C5-FADC-46A5-814F-9ED91259A37F}']
    function GetFooName: string;
  end;

  IBar = interface
    ['{5DEC09C5-FADC-46A5-814F-9ED91259A37F}']
    procedure Dummy;
    function GetBarName: string;
  end;

  TFooBar = class(TInterfacedObject, IFoo, IBar)
    function GetFooName: string;
    function GetBarName: string;
    procedure Dummy;
  end;

function TFooBar.GetFooName: string;
begin
  Result := 'Foo';
end;

procedure TFooBar.Dummy;
begin
  Writeln('Dummy called !');
  // this is procedure without result !
  // yet it might don't raise an exception here because the result in a register could be 0 or valid value
end;

function TFooBar.GetBarName: string;
begin
  Result := 'Bar';
end;

var
  i: IInterface;
begin
  i := TFooBar.Create;
  Writeln((i as IFoo).GetFooName);
  Writeln((i as IBar).GetBarName);
  Readln;
end.

The result

Dummy called !

Bar

 

  • Sad 1

Share this post


Link to post
4 hours ago, Stefan Glienke said:

RTTI does have nothing to do with it but TObject.GetInterfaceEntry - try the following code:

......

....

The interesting thing with those two interfaces in the RTL is that coincidentally they will not cause any harm because of how they are implemented and related to each other - the one inherits from the other and they are also implemented by classes that inherit from each other.

Uhmmm for me it's not working, but maybe I'm missing something...
I'm almost certain that the "as" and "is" don't work if the GUIs are identical...

 

image.thumb.png.574a78ca5eef39c344fa028af3f47398.png

Edited by DelphiUdIT

Share this post


Link to post

That was the point to show how it gives you the wrong one if two interfaces have the same GUID. :classic_rolleyes:

 

The interfaces and their implementation in the RTL inherit from each other so their IMT overlap and the implementations don't differ between those two so there is does not matter.

Simply try that for yourself by inheriting one of the interfaces in my example from the other.

Edited by Stefan Glienke

Share this post


Link to post

May be, now is working, like the example in the Embarcadero unit .... but there are some facets to evaluate.

 

image.thumb.png.24530d69c4cddb2e11fe2a172af52f5b.png

program Project2;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  IFoo = interface
    ['{5DEC09C5-FADC-46A5-814F-9ED91259A37F}']
    function GetEmptyName: string;
    function GetFooName: string;
  end;

  IBar = interface(IFoo)
    ['{5DEC09C5-FADC-46A5-814F-9ED91259A37F}']
    function GetBarName: string;
  end;
  
  //TFooBar = class(TInterfacedObject, IBar) //This is working too
  TFooBar = class(TInterfacedObject, IFoo, IBar)
    function GetEmptyName: string;
    function GetFooName: string;
    function GetBarName: string;
  end;

function TFooBar.GetEmptyName: string;
begin
  Result := 'Empty';
end;

function TFooBar.GetFooName: string;
begin
  Result := 'Foo';
end;

function TFooBar.GetBarName: string;
begin
  Result := 'Bar';
end;

var
  i: IInterface;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
  i := TFooBar.Create;
  Writeln((i as IFoo).GetEmptyName);
  Writeln((i as IFoo).GetFooName);
  Writeln((i as IBar).GetBarName);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  readln;
end.
Edited by DelphiUdIT

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×