unit genericinterface;
{
The ability to add a COM interface to existing classes
that do not inherit from TInterfacedObject.
Currently limited to classes with a simple constructor create.
An enhanced version is available on request:
thaddydekoning[at]gmail[dot]com
Copyright (c) 2024,2025 Thaddy de Koning
M.I.T. licensed.
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
}
{$if fpc_fullversion < 30301}{$error needs fpc 3.3.1 or higher }{$ifend}
{$mode delphi}{$interfaces COM}
interface
uses sysutils, classes;
type
{ Our own little interface }
IInterfaced = interface
['{ADEAD83C-06E1-41A5-A40B-C19D06FE8B9F}']
end;
TInterfaced<T:class,constructor> = class(T,IInterfaced)
strict private
class var
frefcount:integer;
strict protected
{ winapi is cross platform: the compiler chooses the right calling convention, also on e.g. Linux }
function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;
out obj) : longint;winapi;
function _AddRef : longint;winapi;
function _Release : longint;winapi;
public
procedure AfterConstruction;override;
procedure BeforeDestruction;override;
class constructor create;
class function NewInstance : TObject;override;
class property refcount:integer read FRefcount;
end;
implementation
function TInterfaced<T>.QueryInterface(
{$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;winapi;
begin
if GetInterface(iid,obj) then
result:=S_OK
else
result:=longint(E_NOINTERFACE);
end;
function TInterfaced<T>._AddRef : longint;winapi;
begin
_addref:=InterlockedIncrement(frefcount);
end;
function TInterfaced<T>._Release : longint;winapi;
begin
Result := InterlockedDecrement(frefcount);
if Result = 0 then
Destroy;
end;
procedure TInterfaced<T>.AfterConstruction;
begin
InterlockedDecrement(frefcount);
end;
procedure TInterfaced<T>.BeforeDestruction;
begin
// should not happen, does not warrant exception use
if frefcount <> 0 then
halt(204);
end;
class function TInterfaced<T>.NewInstance : TObject;
begin
result:= inherited NewInstance;
TInterfaced<T>(result).frefcount := 1;
end;
class constructor TInterfaced<T>.create;
begin
FRefcount := 0;
end;
end.