XPInterfacedObject.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:7k
源码类别:

Email服务器

开发平台:

Delphi

  1. unit XPInterfacedObject;
  2. {
  3.  $Source: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/Common/XPInterfacedObject.pas,v $
  4.  $Revision: 1.2 $
  5.  $Date: 2004/05/03 15:07:15 $
  6.  Last amended by $Author: pvspain $
  7.  $State: Exp $
  8.  TXPInterfacedObject is a utility base class which implements the base
  9.  interface, ie IUnknown for D5, or IInterface for D6+ and K1+
  10.  What is missing from D5 documentation and barely mentioned in D6 is the need
  11.  to deflect all reference counting to the container (owner) class, when
  12.  delegating to an interface-type property or to a class-type property which
  13.  implements (directly or in an ancestor) IInterface/IUnknown.
  14.  TXPInterfacedObject subclasses TInterfacedObject and correctly handles
  15.  reference counting when it provides its interface directly to clients, or
  16.  indirectly, when a container interfaced object is using interface delegation.
  17.  To indicate a delegated context, pass a non-nil ADelegator parameter to the
  18.  TXPInterfacedObject constructor
  19.  Delphi 6 introduced the TAggregatedObject class to handle the delegated
  20.  context, but it does so unconditionally, ie you must know a-priori if your
  21.  class will be exclusively in either a primary implementor context (use
  22.  TInterfacedObject) or a delegated implementor context (use TAggregatedObject).
  23.  To my thinking this design decision is too inflexible, and this is the reason
  24.  for writing our own solution to the reference counting deflection problem.
  25.  Delphi 6 also saw the introduction of TContainedObject, which is a subclass of
  26.  TAggregatedObject that doesn't deflect QueryInterface() calls to its
  27.  Delegator/Container object. I have added the Introspective property to
  28.  TXPInterfacedObject to support this behaviour. Introspective is false by
  29.  default, and QueryInterface() calls will deflect to the Delegator object, if
  30.  defined. When Introspective is true, QueryInterface calls will be resolved by
  31.  this object.
  32.  When ref count redirection is active, there is no longer a mechanism for the
  33.  Delegated object's destructor to be called automatically - _Release calls are
  34.  handled by the Delegator. Therefore, to avoid memory leakage, the Delegator
  35.  must explicitly destroy the Delegated object. It follows that the Delegator
  36.  must always delegate to a class-type property, not an interface-type property,
  37.  to be able to call the Delegated destructor. The Delegator should call the
  38.  Delegated destructor in the context of its own destructor.
  39.  Copyright (c) 2001,2003 by The Excellent Programming Company Pty Ltd
  40.  (Australia) (ABN 27 005 394 918).
  41.  Contact Paul Spain via email: paul@xpro.com.au
  42.  This unit is free software; you can redistribute it and/or
  43.  modify it under the terms of the GNU Lesser General Public
  44.  License as published by the Free Software Foundation; either
  45.  version 2.1 of the License, or (at your option) any later version.
  46.  This unit is distributed in the hope that it will be useful,
  47.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  48.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  49.  Lesser General Public License for more details.
  50.  You should have received a copy of the GNU Lesser General Public
  51.  License along with this unit; if not, the license can be viewed at:
  52.  http://www.gnu.org/copyleft/lesser.html
  53.  or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  54.  Boston, MA  02111-1307  USA
  55.  }
  56. interface
  57. {$I JEDI.inc}
  58. ///////////////////////////////////////////////////////////////////////////////
  59. ///     TXPInterfacedObject declaration
  60. ///////////////////////////////////////////////////////////////////////////////
  61. type
  62. // Conditional types for Delphi 4 & 5
  63. {$IFNDEF DELPHI6_UP}
  64.   IInterface = IUnknown;
  65. {$ENDIF}
  66.   TXPInterfacedObject = class(TInterfacedObject, IInterface)
  67.   private
  68.     FDelegator: Pointer;  // weak reference to delegator/container for delegated
  69.                           // interface implementation ( = nil for direct
  70.                           // implementation )
  71.     FIntrospective: boolean;
  72.     function GetDelegator: IInterface;
  73.     procedure SetIntrospective(const Value: boolean);
  74.   protected
  75.     //
  76.     // IInterface re-implementation
  77.     //
  78.     function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  79.     function _AddRef: integer; stdcall;
  80.     function _Release: Integer; stdcall;
  81.   public
  82.     constructor Create(const ADelegator: IInterface = nil);
  83.     property Delegator: IInterface read GetDelegator;
  84.     // Defaults to false. When true, QueryInterface() will only return
  85.     // interfaces implemented by this object, not by the delegating host 
  86.     property Introspective: boolean read FIntrospective write SetIntrospective;
  87.   end;
  88. implementation
  89. uses
  90.   Windows;
  91. const CVSID: string = '$Header: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/Common/XPInterfacedObject.pas,v 1.2 2004/05/03 15:07:15 pvspain Exp $';
  92. ///////////////////////////////////////////////////////////////////////////////
  93. ///     TXPInterfacedObject implementation
  94. ///////////////////////////////////////////////////////////////////////////////
  95. constructor TXPInterfacedObject.Create(const ADelegator: IInterface);
  96. begin
  97.   inherited Create;
  98.   // weak reference to delegator/container - don't keep it alive
  99.   FDelegator := Pointer(ADelegator);
  100. end;
  101. function TXPInterfacedObject.GetDelegator: IInterface;
  102. begin
  103.   Result := IInterface(FDelegator);
  104. end;
  105. function TXPInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
  106. begin
  107.   if (FDelegator = nil) or FIntrospective then
  108.     Result := inherited QueryInterface(IID, Obj)
  109.   else
  110.     Result := IInterface(FDelegator).QueryInterface(IID, Obj);
  111. end;
  112. procedure TXPInterfacedObject.SetIntrospective(const Value: boolean);
  113. begin
  114.   
  115.   if Value or (FDelegator <> nil) then 
  116.     FIntrospective := Value;
  117.   
  118. end;
  119. function TXPInterfacedObject._AddRef: Integer;
  120. begin
  121.   if FDelegator = nil then
  122.     Result := inherited _AddRef
  123.   else
  124.   begin
  125.     // Separate _AddRef and Result for thread-safety
  126.     IInterface(FDelegator)._AddRef;
  127.     // Although unnecessary in delegated case, maintain FRefCount for use by
  128.     // subclasses (such as XPObserver.TXPSubject)
  129.     Result := Windows.InterlockedIncrement(FRefCount);
  130.   end;
  131. end;
  132. function TXPInterfacedObject._Release: Integer;
  133. begin
  134.   if FDelegator = nil then
  135.     Result := inherited _Release
  136.   else
  137.   begin
  138.     // Although unnecessary in delegated case, maintain FRefCount for use by
  139.     // subclasses (such as XPObserver.TXPTarget)
  140.     Result := Windows.InterlockedDecrement(FRefCount);
  141.     // Separate Result and _Release for thread-safety. Do _Release last to
  142.     // ensure we aren't referencing member data after destruction
  143.     IInterface(FDelegator)._Release;
  144.   end;
  145. end;
  146. end.