mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-06 01:47:59 +02:00

* Allow properties of type interface to implement not just the same interface, but also any of its ancestors. * Allow a single property to implement multiple interfaces. git-svn-id: trunk@18983 -
174 lines
4.4 KiB
ObjectPascal
174 lines
4.4 KiB
ObjectPascal
program MultiIntfDelegation;
|
|
{$mode objfpc}{$h+}
|
|
|
|
type
|
|
IGMGetHandle = interface(IUnknown)
|
|
['{5BB45961-15A9-11d5-A5E4-00E0987755DD}']
|
|
function GetHandle: THandle; stdcall;
|
|
property Handle: THandle read GetHandle;
|
|
end;
|
|
|
|
IGMGetFileName = interface(IUnknown)
|
|
['{D3ECCB42-A563-4cc4-B375-79931031ECBA}']
|
|
function GetFileName: String; stdcall;
|
|
property FileName: String read GetFileName;
|
|
end;
|
|
|
|
IGMGetSetFileName = Interface(IGMGetFileName)
|
|
['{ECFB879F-86F6-41a3-A685-0C899A2B5BCA}']
|
|
procedure SetFileName(const Value: String); stdcall;
|
|
property FileName: String read GetFileName write SetFileName;
|
|
end;
|
|
|
|
|
|
{ TImplementor }
|
|
|
|
TImplementor = class(TObject, IGMGetHandle, IGMGetFileName, IGMGetSetFileName)
|
|
protected
|
|
FController: Tobject;
|
|
|
|
public
|
|
constructor Create(const AController: TObject);
|
|
|
|
function QueryInterface(constref IID: TGUID; out Intf): HResult; virtual; {$ifdef windows}stdcall{$else}cdecl{$endif};
|
|
function _AddRef: LongInt; virtual; {$ifdef windows}stdcall{$else}cdecl{$endif};
|
|
function _Release: LongInt; virtual; {$ifdef windows}stdcall{$else}cdecl{$endif};
|
|
|
|
function GetHandle: THandle; stdcall;
|
|
function GetFileName: String; stdcall;
|
|
procedure SetFileName(const Value: String); stdcall;
|
|
end;
|
|
|
|
|
|
{ TIntfDelegator }
|
|
|
|
TIntfDelegator = class(TInterfacedObject, IGMGetFileName, IGMGetSetFileName)
|
|
protected
|
|
FImplementor: TImplementor;
|
|
FGetSetFileName: IGMGetSetFileName;
|
|
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
//
|
|
// This would be nice. NOTE: IGMGetFileName is derived from IGMGetSetFileName!
|
|
//
|
|
property Implementor: IGMGetSetFileName read FGetSetFileName implements IGMGetFileName, IGMGetSetFileName;
|
|
end;
|
|
|
|
|
|
{ TObjDelegator }
|
|
|
|
TObjDelegator = class(TInterfacedObject, IGMGetHandle, IGMGetFileName, IGMGetSetFileName)
|
|
protected
|
|
FImplementor: TImplementor;
|
|
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
//
|
|
// This would be really smart!
|
|
//
|
|
property Implementor: TImplementor read FImplementor implements IGMGetHandle, IGMGetFileName, IGMGetSetFileName;
|
|
end;
|
|
|
|
|
|
|
|
{ TImplementor }
|
|
|
|
constructor TImplementor.Create(const AController: TObject);
|
|
begin
|
|
FController := AController;
|
|
end;
|
|
|
|
function TImplementor.QueryInterface(constref IID: TGUID; out Intf): HResult; {$ifdef windows}stdcall{$else}cdecl{$endif};
|
|
var PIUnkController: IUnknown;
|
|
begin
|
|
if GetInterface(IID, Intf) then Result := S_OK else
|
|
if (FController <> nil) and FController.GetInterface(IUnknown, PIUnkController) then
|
|
Result := PIUnkController.QueryInterface(IID, Intf) else Result := E_NOINTERFACE;
|
|
end;
|
|
|
|
function TImplementor._AddRef: LongInt; {$ifdef windows}stdcall{$else}cdecl{$endif};
|
|
var PIUnkController: IUnknown;
|
|
begin
|
|
if (FController <> nil) and FController.GetInterface(IUnknown, PIUnkController) then
|
|
Result := PIUnkController._AddRef
|
|
end;
|
|
|
|
function TImplementor._Release: LongInt; {$ifdef windows}stdcall{$else}cdecl{$endif};
|
|
var PIUnkController: IUnknown;
|
|
begin
|
|
if (FController <> nil) and FController.GetInterface(IUnknown, PIUnkController) then
|
|
Result := PIUnkController._Release
|
|
end;
|
|
|
|
function TImplementor.GetHandle: THandle; stdcall;
|
|
begin
|
|
writeln('TImplementor.GetHandle');
|
|
Result := 0;
|
|
end;
|
|
|
|
function TImplementor.GetFileName: String; stdcall;
|
|
begin
|
|
writeln('TImplementor.GetFileName');
|
|
Result := '';
|
|
end;
|
|
|
|
procedure TImplementor.SetFileName(const Value: String); stdcall;
|
|
begin
|
|
writeln('TImplementor.SetFileName');
|
|
end;
|
|
|
|
|
|
{ TIntfDelegator }
|
|
|
|
constructor TIntfDelegator.Create;
|
|
begin
|
|
FImplementor := TImplementor.Create(Self);
|
|
FGetSetFileName := FImplementor;
|
|
end;
|
|
|
|
destructor TIntfDelegator.Destroy;
|
|
begin
|
|
FImplementor.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
{ TObjDelegator }
|
|
|
|
constructor TObjDelegator.Create;
|
|
begin
|
|
FImplementor := TImplementor.Create(Self);
|
|
end;
|
|
|
|
destructor TObjDelegator.Destroy;
|
|
begin
|
|
FImplementor.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
var
|
|
PIUnk: IUnknown;
|
|
PIGetFileNAme: IGMGetFileName;
|
|
PIGetSetFileName: IGMGetSetFileName;
|
|
obj: TObjDelegator;
|
|
begin
|
|
PIUnk := TIntfDelegator.Create;
|
|
PIUnk.QueryInterface(IGMGetFileName, PIGetFileName);
|
|
PIGetFileName.GetFileName;
|
|
PIUnk.QueryInterface(IGMGetSetFileName, PIGetSetFileName);
|
|
PIGetSetFileName.SetFileName('');
|
|
|
|
obj := TObjDelegator.Create;
|
|
(obj as IGMGetFileName).GetFileName;
|
|
(obj as IGMGetSetFileName).SetFileName('');
|
|
(obj as IGMGetHandle).GetHandle;
|
|
end.
|
|
|
|
|