7. FireMonkey–Funktionen von einer VCL-Anwendung per DLL nutzen

Der Umbau einer bestehenden VCL-Anwendung zur FireMonkey-Anwendung kann in einer "radikalen" Vorgehensweise erfolgen. Also alles in einem Rutsch  konvertieren. Nachteil dabei ist, dass dies bei einem größeren VCL-Projekt sehr lange dauern kann  und man an der aktuellen Anwendung dann sinnvoller Weise nicht mehr viel verändert.

Die Alternative zu dieser Vorgehensweise könnte ein sanfter Übergang sein. Indem man z.B. Schritt für Schritt Dialoge und zugehörige Funktionen in eine FireMonkey-DLL auslagert und somit den Übergang sukzessive bewirkt. Dabei kann man auch gleich die neuen erweiterten Möglichkeiten (Grafik, Ortungsfunktionen, etc.) einbauen, so dass die aktuelle Anwendung direkt davon profitieren kann.

Möglicherweise wollen Sie aber auch (noch) nicht von VCL auf das FireMonkey-Framework umsteigen, würden aber gerne bestimmte Funktionalitäten von FireMonkey nutzen. In beiden Varianten bietet es sich an, diese Funktionalitäten über eine FireMonkey-DLL zur Verfügung zu stellen. Das ist gar nicht so schwer, es funktioniert so ähnlich wie unter der VCL.

Hier zeige ich an einem Beispiel, wie ich meinem VCL-Bildbearbeitungsprogramm „PixPower Photo & Draw“ einen neuen Filtereffekt über eine FireMonkey-DLL hinzugefügt habe. Die erzeugte DLL hat dabei eine Größe von ca. 4 MB, wirkt sich auf mein komprimiertes Installationspaket aber nur mit einem Umfang von 1,3 MB aus. In den kommenden Wochen werde ich hier noch weitere Filter hinzufügen.

Kurze Erläuterung der gewünschten Funktionalität: In der VCL-Anwendung habe ich also eine Bitmap, die ich als Bitmap-Stream speichere und an die FMX-DLL übergebe. Die Bitmap kann ich leider nicht direkt als „TBitmap“ an die DLL übergeben, da VCL- und FireMonkey-Bitmap untereinander nicht kompatibel sind. In der DLL wird die Bitmap in einem Dialog in der Imageviewer-Komponente angezeigt, der ich einen Papersketch-Effekt hinzugefügt habe. Die Intensität wird über eine Trackbar eingestellt.

Wenn der Anwender das dann mit „OK“ bestätigt, wird der PaperSketch Effekt auf die Bitmap tatsächlich angewandt und  und die Bitmap wieder in den Stream geschrieben. Hier muss allerdings noch ein kleiner Trick benutzt werden, denn standardmäßig schreibt FireMonkey einen Bitmapstream als PNG-Stream. Daher wird eine eigene Klasse „TMyBitmap“ von TBitmap abgeleitet und die SaveStream-Prozedur überschrieben und so angepasst, dass der Stream als Bitmap-Stream ("BMP"-Format bzw. RGB) gespeichert werden kann.

Hier nun der konkrete Ablauf zur Erzeugung der FMX-DLL: Legen Sie über Menü „Datei“, Befehl „Neu“ eine Dynamische Link-Bibliothek an:

library FMXFilters;

uses
FMX.Forms,

System.SysUtils,
System.Classes,

FrmFilter in 'FrmFilter.pas' {F_Filters};

{R *.res}

exports
ShowBitmapFromStream;


begin
end.

Wenn Sie die Bibliothek angelegt haben, sind die hier in Fettschrift gekennzeichneten Elemente noch nicht vorhanden.

Die Unit FMX.Forms müssen Sie manuell hinzufügen, damit klar ist, dass es sich um eine FireMonkey-DLL handeln soll. Je nachdem, ob Sie die Library bei einem bereits geöffneten VCL-Projekt anlegen oder separat, kann es sein, dass Delphi darauf hinweist, dass für die DLL hier ein FireMonkey-Projekt angenommen wird und daher eine entsprechende Kennzeichnung vorgenommen werden müsste. Diese Abfrage können Sie dann positiv bestätigen.

Die Unit FrmFilter ist eine Formularunit, die ich über den Befehl „Datei“, „Neu“, „FireMonkey-Formular“ angelegt habe.

Achtung: Dieser Befehl wird nur angezeigt, wenn Sie das DLL-Projekt im Projekt-Explorer angezeigt haben:
 


Das Formular sieht dabei so aus:


Im Struktur-Explorer so:


Im Source-Code habe ich vor dem „Implementation“ die folgende Funktion definiert:

Function ShowBitmapFromStream (ms: TMemoryStream): Boolean; export;

Das ist die Funktion, die über die „exports“ Anweisung in der Library-Datei als extern aufrufbare Funktion zur Verfügung gestellt wird.

Hinweis 1: Wenn Sie statt einer Bitmap einen String an die DLL übergeben möchten, sollten Sie entweder ShortString, PChar oder WideString dafür verwenden. Das erspart Ihnen, die ShareMem-Unit aufnehmen zu müssen und die BORLNDMM.DLL noch mit Ihrer Anwendung weitergeben zu müssen.

Hinweis 2: Wenn Sie erreichen wollen, dass die erzeugte DLL nicht nur von Delphiprogrammen, sondern auch von Programmen, die mit anderen Entwicklungsumgebungen erzeugt wurden, aufgerufen werden können, sollten Sie einen „IStream“, statt einen TMemoryStream verwenden.

Hier die Implementation dieser Funktion in der Formdatei (unter Uses werden noch die Units FMX.Filter, FMX.Effects, FMX.Filter.Effects und FMX.Surfaces benötigt):

function ShowBitmapFromStream (ms: TMemoryStream): Boolean;
var
  Filter: FMX.Filter.TFilter;
begin
  Filter := TFilterManager.FilterByName('PaperSketch');

  try
    F_Filters := TF_Filters.Create(Application);
    F_Filters.ImageViewer1.bitmap.LoadFromStream(ms);

    if F_Filters.ShowModal = mrOK then begin

      Filter.ValuesAsBitmap['Input'] := F_Filters.ImageViewer1.bitmap;
      Filter.ValuesAsFloat ['BrushSize'] := F_Filters.TrackBar1.Value;
      F_Filters.ImageViewer1.bitmap := TBitmap (Filter.ValuesAsBitmap['Output']);

      TMyBitmap (F_Filters.ImageViewer1.bitmap).SaveToStream (ms);

      Result := True;
   end else begin
     Result := false;
  end;

  finally
    F_Filters.Free;
  end;
end;
 

Hier noch die benötigte Anpassung zur Speicherung des Bitmap-Streams im BMP-Format:

Type
TMyBitmap = class (TBitmap)
   procedure SaveToStream(Stream: TStream);
end;

Implementation

procedure TMyBitmap.SaveToStream(Stream: TStream);
var
  Surf: TBitmapSurface;
begin
  Surf := TBitmapSurface.Create;
  try
     Surf.Assign(Self);
     TBitmapCodecManager.SaveToStream(Stream, Surf, '.bmp');
  finally
    Surf.Free;
  end;
end;

Erläuterung: Über den FilterManager wird also zunächst über den Namen des Filters bzw. Effektes „PaperSketch“ die Filterfunktion vorbelegt. Dann wird der FMX-Dialog erzeugt, der Bitmap-Stream wird in die Bitmap des Imageviewers geladen.

Wenn der Anwender über die Trackbar die gewünschte Intensität des Effektes eingestellt hat und die Aktion mit „OK“ bestätigt, wird die Einstellung der Trackbar mit Hilfe der Filterfunktionen auf die Bitmap im Imageviewer tatsächlich angewendet (der PaperSketch-Effekt in der Form verändert ja das Bitmap des Imageviewers nicht, geändert wird nur die Anzeige in der Form).

Dann wird die geänderte Bitmap mit der abgeleiteten Klasse als „BMP"-Bitmap- Stream gespeichert (also eine Bitmap im RGB-Format).

In der VCL-Anwendung ist nun folgende Unit hinzuzufügen: 

unit uFMXLink;
interface
uses
  Windows, Dialogs, Classes;
type
  TShowBitmapFromStream = function(ms: TMemoryStream): Boolean;

var
  ShowBitmapFromStream : TShowBitmapFromStream = nil;
  DllHandle : THandle;

implementation
initialization
  if DllHandle = 0 then begin
    DllHandle := LoadLibrary('FMXFilters.dll');
    if DllHandle > 0 then begin
     @ShowBitmapFromStream := GetProcAddress(DllHandle,
       'ShowBitmapFromStream');
    End else begin
      MessageDlg('ShowBitmapFromStream steht nicht zur Verfügung',  
        mtInformation, [mbOK], 0);
    end;
end;
finalization
if DLLHandle <> 0 then
  FreeLibrary(DLLHandle);
end.

Erläuterung: Unter Type wird eine Funktion definiert, die der exportieren Funktion aus der DLL entspricht. Unter Var wird wird ShowBitmapFromStream dann als Procedur-Variable eingeführt.

Im Initialization-Abschnitt wird die DLL geladen und bei Erfolg dann die Speicheradresse ermittelt und unserer zuvor deklarierten Prozedur zugewiesen. Wenn Sie dann diese VCL-Unit in Ihre VCL-Anwendung einbinden, können Sie dann von Ihrem Hauptformular aus die Funktion „ShowBitmapFromStream“ aufrufen.

Also z.B. So:

Var
  MemStream: TMemorySteam;
Begin
  ABitmap.saveToStream (MemStream); // Bitmap als MemoryStream 
  MemStream.position := 0;
  If ShowBitmapFromStream (MemStream) then begin
     MemStream.Position := 0;
     ABitmap.LoadFromStream (ms) //Datei wieder in Bitmap laden
End;

ACHTUNG: Damit das funktioniert, muss in die Hauptform Ihrer VCL-Anwendung die Windows-Unit „Winapi.GDIPOBJ“ eingebunden werden und zwar direkt im USES-Abschnitt des Inteface-Abschnitts (also nicht in einer Uses-Klausel im Implementations-Abschnitt, das wäre nicht ausreichend).

Diese Unit wird benötigt, damit die GDI-Funktionalität auch für die VCL-Anwendung initialisiert werden kann. Das kann nur über das Hauptprogramm gemacht werden, in die FireMonkey-Unit gehört das also nicht rein.

Wenn Sie Interesse haben, können Sie sich die Funktionalität in dem Programm einmal ansehen (www.Pixpower.info) oder ganz einfach in einem YouTube-Video in meinem PixPower-Kanal, wo ich diesen Filter präsentiere: http://youtu.be/W21uxyPsJvc.

Den Source-Code für diese Demo können Sie hier laden. Voraussetzung ist  Delphi XE4 oder XE5. Sie müssen sowohl DLL und EXE kompilieren und die DLL muss im gleichen Verzeichnis wie die EXE-Datei liegen.

Nachtrag: Habe noch ein kleines Video erstellt, das zeigt, wie man die FMX-Form auch gleichzeitig in einer FireMonkey-Anwendung verwenden kann.

Hier ist der Link.

Im FireMonkey-Buch können Sie übrigens in Kapitel 4 "Grafikbearbeitung in FireMonkey" unter Nummer 5 "Grafik drehen, spiegeln, invertieren oder grau färben" mehr zur Verwendung der Filter- bzw. Effekt-Funktionen erfahren.

Fazit
Die Einbindung von FireMonkey-Funktionalität über eine FireMonkey-DLL in Ihre VCL-Einwendung ist schnell gemacht. So können Sie entweder Schritt für Schritt VCL-Code zu FireMonkey-Code umbauen oder einfach nur tolle FireMonkey-Funktionen in Ihre VCL-Anwendung einbauen.


Neues FireMonkey Buch verfügbar
Seit dem 10. November gibt es ein neues Buch, das auf die auf die Verwendung von XE4/XE5 angepasst ist.

Hinweis 1: Da das existierende Buch für Delphi XE3 und FireMonkey 2 ja einige Sachverhalte von XE4 bzw. XE5 nicht abdeckt, habe ich den Preis auf 9,89 Euro gesenkt . Für Anwender von XE3 jetzt eine gute Gelegenheit zuzugreifen.

Hinweis 2: Das neue Buch für XE4/XE5 kostet 24,99 Euro.

Hinweis 3: Ist eigentlich mehr eine Bitte. Wenn mein Buch Ihnen als Leser eine Hilfe war, wäre ich dankbar, wenn Sie bei Amazon eine entsprechend positive Kritik abgeben könnten. Ohne das geht es kaum bei Amazon. 

Also, was ist Ihre Meinung zur Verwendung zu Delphi XE5 und FireMonkey, wie sind Ihre eigenen  Erfahrungen? Wenn Sie Anregungen zu Themen haben, lassen Sie es mich gerne wissen. Meine Mailadresse finden Sie oben auf der Seite unter dem Link "Anbieterkennzeichnung & Kontakt". Über meinen Hastasoft-Twitter Account werde ich posten, wenn neue Blogbeiträge zur Verfügung stehen. Wenn Sie wollen, klinken Sie sich dort ein (siehe meine Hastasoft-Seite).

Viel Erfolg mit Delphi und FireMonkey!

Harry Stahl, 13.02.2014