You could make resizeBitmap() be a class method of a Generic class, eg:
type
TBitmapUtility<T> = class
public
class procedure resizeBitmap(const aBitmap: T; const w, h: integer);
end;
class procedure TBitmapUtility<T>.resizeBitmap(const aBitmap: T; const w, h: integer);
begin
...
end;
Then you can specify either FMX.Graphics.TBitmap or VCL.Graphics.TBitmap as the Generic type:
var
bmp: FMX.Graphics.TBitmap;
TBitmapUtility<FMX.Graphics.TBitmap>.resizeBitmap(bmp, ...);
var
bmp: VCL.Graphics.TBitmap;
TBitmapUtility<VCL.Graphics.TBitmap>.resizeBitmap(...);
If you specify just TBitmap as the type, the compiler can decide to use FMX.Graphics.TBitmap or VCL.Graphics.TBitmap based on which unit you have in the uses clause, which you can control conditionally:
uses
...,
{$IF Declared(FireMonkeyVersion)}
FMX.Graphics,
{$ELSE}
VCL.Graphics,
{$IFEND}
...;
var
bmp: TBitmap;
TBitmapUtility<TBitmap>.resizeBitmap(bmp, ...);
Or, use the project's "Unit Scope Names" list instead:
uses
...,
Graphics, // <-- specify either 'Vcl' or 'Fmx' in the Unit Scope Names list...
...;
var
bmp: TBitmap;
TBitmapUtility<TBitmap>.resizeBitmap(bmp, ...);
With that said, you do run into a problem - FMX.Graphics.TBitmap and VCL.Graphics.TBitmap do not have a common ancestor beyond TPersistent, so you can't apply a Generic contraint to T so code like this can compile:
class procedure TBitmapUtility<T>.resizeBitmap(const aBitmap: T; const w, h: integer);
begin
aBitmap.Width := w;
aBitmap.Height := h;
end;
You will have to resort to using RTTI to solve this, eg:
uses
..., System.Rtti;
type
TBitmapUtility<T: class> = class
public
class procedure resizeBitmap(const aBitmap: T; const w, h: integer);
end;
class procedure TBitmapUtility<T>.resizeBitmap(const aBitmap: T; const w, h: integer);
var
Ctx: TRttiContext;
Typ: TRttiType;
begin
Typ := Ctx.GetType(TypeInfo(T));
Typ.GetProperty('Width').SetValue(Pointer(aBitmap), w);
Typ.GetProperty('Height').SetValue(Pointer(aBitmap), h);
end;
Or:
class procedure TBitmapUtility<T>.resizeBitmap(const aBitmap: T; const w, h: integer);
var
Ctx: TRttiContext;
Typ: TRttiType;
Mth: TRttiMethod;
begin
Typ := Ctx.GetType(TypeInfo(T));
Mth := Typ.GetMethod('Resize'); // FMX
if Mth = nil then
Mth := Typ.GetMethod('SetSize'); // VCL
// or use an $IF/$IFDEF to decide which method to lookup...
if Mth <> nil then
Mth.Invoke(TObject(aBitmap), [w, h])
else
begin
Typ.GetProperty('Width').SetValue(Pointer(aBitmap), w);
Typ.GetProperty('Height').SetValue(Pointer(aBitmap), h);
end;
end;
Actually, if you go the {$IF} or "Unit Scope Names" list approach, and let the compiler decide which TBitmap type to use, then you don't actually need the Generic at all, and don't need RTTI when accessing properties/methods that are common to both TBitmap types (even though they don't have a common ancestor):
uses
...,
{$IF Declared(FireMonkeyVersion)}
FMX.Graphics,
{$ELSE}
VCL.Graphics,
{$ENDIF}
// or, just 'Graphics' unconditionally...
...;
procedure resizeBitmap(const aBitmap: TBitmap; const w, h: integer);
...
procedure resizeBitmap(const aBitmap: TBitmap; const w, h: integer);
begin
aBitmap.Width := w;
aBitmap.Height := h;
end;
...
var
bmp: TBitmap;
resizeBitmap(bmp, ...);
resizeBitmap()be a class method of a Generic class, then specify eitherFMX.Graphics.TBitmaporVCL.Graphics.TBitmapas the Generic type. If you specify justTBitmapas the type, the compiler can decide to useFMX.Graphics.TBitmaporVCL.Graphics.TBitmapbased on which unit you have in theusesclause, which you can control conditionally with an{$IFDEF}or via the project's "Unit Scope Names" list. But no, there is no predefined compiler directive that you canIFDEFon to know if you are compiling for FMX or VCL, you have to make your own for that purpose. - Remy Lebeau