![]() |
Delphi-Version: 10.1 Berlin
FMX und VCL verbinden
Liste der Anhänge anzeigen (Anzahl: 1)
Huhu Gemeinde!
Ich probiere seit einigen Tagen diverse Möglichkeiten durch, um innerhalb einer VCL Anwendung FireMonkey zum laufen zu bringen. Letztendlich bin über ![]() ![]() Ich schaffe es immer wieder eine access violation zu erzeugen (Screenshot im Anhang). Hoffentlich habe ich an alles gedacht, sodass ihr euch ein gutes Bild machen könnt. Ziel ist es wie gesagt für mich im ersten Schritt aus dem VCL Formular das FMX Formular zu öffnen. Vielleicht bin ich da schon irgendwie auf dem falschen Dampfer. ^^ Ich danke euch schon mal für alle Vorschläge und Hinweise. :) Die Ordner-Struktur meines Projekts sieht so aus: Projektpfad C:\Users\USERNAME\Documents\Embarcadero\Studio\Pro jekte\Neuer Ordner Debugpfad (inklusive exe und DLL) C:\Users\USERNAME\Documents\Embarcadero\Studio\Pro jekte\Neuer Ordner\Win32\Debug Die DLL ist ganz wie im Beispiel von Harry Stahl aufgebaut:
Delphi-Quellcode:
Die FMX Form beinhaltet lediglich nur ungenutzte Elemente, damit es nicht ganz so leer ist. Die Funktion ist auch eher ein Dummy:
library ProjectDLL;
uses System.SysUtils, System.Classes, FMX.Forms, Unit1FMX in 'Unit1FMX.pas' {Form1}; {$R *.res} exports TestFunc; begin end.
Delphi-Quellcode:
Jetzt kommen wir zur VCL Form. Ich werde mich hier auf die wesentlichen Funktionen beschränken:
unit Unit1FMX;
interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Filter, FMX.Effects, FMX.Filter.Effects, FMX.Surfaces, FMX.StdCtrls, FMX.Layouts, FMX.ExtCtrls, FMX.Controls.Presentation, FMX.Objects, FMX.Calendar; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; TrackBar1: TTrackBar; ImageViewer1: TImageViewer; Label1: TLabel; Calendar1: TCalendar; CalloutRectangle1: TCalloutRectangle; private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; function testfunc : Boolean; export; implementation {$R *.fmx} function testfunc : Boolean; begin result := false; end; end.
Delphi-Quellcode:
{...Unit, Interface, Uses, TForm1...}
type TTestFunc = function : Boolean; var Form1: TForm1; TestFunc: TTestFunc = nil; DllHandle: THandle; implementation {$R *.dfm} {...Funktionen...} procedure TForm1.Button2Click(Sender: TObject); begin TestFunc; end; {...Funktionen...} initialization if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle > 0 then begin @TestFunc := GetProcAddress(DllHandle, 'TestFunc'); End else begin MessageDlg('TestFunc steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle); end. |
AW: FMX und VCL verbinden
Und bei
Delphi-Quellcode:
:?:
procedure TForm1.Button2Click(Sender: TObject);
begin if Assigned(TestFunc) then TestFunc; end; |
AW: FMX und VCL verbinden
Ok es crasht nicht mehr. Worauf genau prüft "Assigned"?
Beim Debuggen fiel mir noch auf, dass an der Stelle:
Delphi-Quellcode:
GetProcAddress = nil zurückgibt.
initialization
if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle > 0 then begin @TestFunc := GetProcAddress(DllHandle, 'TestFunc'); End else begin MessageDlg('TestFunc steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; Das kann doch eigentlich nicht sein, wenn der DllHandle richig überschrieben wurde, oder doch? An der Stelle LoadLibrary kriegt das DllHandle auch einen plausiblen Wert zugewiesen. |
AW: FMX und VCL verbinden
Hi,
verwende überall die gleiche Schreibweise...
Delphi-Quellcode:
function testfunc...
exports TestFunc; |
AW: FMX und VCL verbinden
Zitat:
|
AW: FMX und VCL verbinden
Wenn ich da nichts übersehe, machst du da einen Pointer auf nil. TestFunc ist mit nil initialisiert und so führt @nil zu einer Access Violation. Also einfach das @ entfernen und es sollte gehen.
TestFunc := GetProcAddress(DllHandle, 'TestFunc'); Warum importierst du die Funktion nicht einfach wie folgt. So brauchst du das ganze Load/FreeLibrary Zeugs nicht. Deine DLL muss ja eh immer vorhanden sein. Also macht es keinen Sinn, diese zur Runtime als Latebinding zu laden. Mit dieser Art der DLL Einbindung, wird die DLL automatisch beim Programmstart geladen. Ist also deutlich einfacher.
Delphi-Quellcode:
Lies dir mal in der Hilfe die Beschreibung zu "external":
{...Unit, Interface, Uses, TForm1...}
function TestFunc(): Boolean; var Form1: TForm1; DllHandle: THandle; implementation {$R *.dfm} {...Funktionen...} procedure TForm1.Button2Click(Sender: TObject); begin TestFunc; end; {...Funktionen...} function TestFunc; external 'ProjectDLL.dll' name 'TestFunc'; { Das brauchst du in diesem Fall nicht, da die DLL durch die obige Deklaration automatisch beim Programmstart geladen wird. initialization if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle <= 0 then begin MessageDlg('ProjectDLL.dll steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle); } end. ![]() |
AW: FMX und VCL verbinden
Ich hab das mal getestet, mir wird die Funktion "TestFunc" jetzt als überladen angezeigt. Dies scheint mir aber nicht so plausibel zu sein, da keine Parameter übergeben werden. Es kommt lediglich ein boolscher Wert zurück.
Ich habe mich auch nebenbei an dem Hydra Framework probiert. Das wäre aber ein anderes Thema. Dort verzweifel ich ähnlich wie hier. ^^ |
AW: FMX und VCL verbinden
Zitat:
Vielleicht deswegen?
Delphi-Quellcode:
function testfunc : Boolean;
begin result := false; end; |
AW: FMX und VCL verbinden
Zitat:
Betreffs dem "überladen" hast du wohl nun diese Funktion 2x in deinem Code. Poste mal deinen aktuellen Quellcode, wenn du es nicht selber siehst. Mach am besten eine eigene Unit mit den ganzen Funktionen/Proceduren der DLL und dann hast im Interface die Definitionen und im der Implementation die Verbindung zu externen DLL. Also in etwa so:
Delphi-Quellcode:
unit ProjectDLLInterface;
interface function TestFunc: Boolean; procedure ShowMyFMXForm(); implementation function TestFunc: Boolean; external 'ProjectDLL.dll' name 'TestFunc'; procedure ShowMyFMXForm(); external 'ProjectDLL.dll' name 'ShowMyFMXForm'; end. |
AW: FMX und VCL verbinden
Puh also für mich wird's langsam schon unübersichtlich.
Zitat:
Zitat:
DLL:
Delphi-Quellcode:
FMX:
library ProjectDLL;
uses System.SysUtils, System.Classes, FMX.Forms, Unit1FMX in 'Unit1FMX.pas' {FMXForm1}; {$R *.res} exports //TestFunc, TestProc; begin end.
Delphi-Quellcode:
Main Unit:
unit Unit1FMX;
interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Filter, FMX.Effects, FMX.Filter.Effects, FMX.Surfaces, FMX.StdCtrls, FMX.Layouts, FMX.ExtCtrls, FMX.Controls.Presentation, FMX.Objects, FMX.Calendar; type TFMXForm1 = class(TForm) Button1: TButton; Button2: TButton; TrackBar1: TTrackBar; ImageViewer1: TImageViewer; Label1: TLabel; Calendar1: TCalendar; CalloutRectangle1: TCalloutRectangle; private { Private-Deklarationen } public { Public-Deklarationen } end; var FMXForm1: TFMXForm1; function TestFunc : Boolean; export; procedure TestProc; export; implementation {$R *.fmx} procedure TestProc; begin FMXForm1.Show; end; function testfunc : Boolean; begin result := false; end; end.
Delphi-Quellcode:
ProjectDLLInterface
unit UnitMain;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Data.Win.ADODB, Vcl.StdCtrls, Vcl.ExtCtrls, Datasnap.DBClient, Vcl.Grids, Vcl.DBGrids, Vcl.Mask, Vcl.DBCtrls, Datasnap.Provider, UnitDBM, UnitRB; type TForm1 = class(TForm) DBGrid2: TDBGrid; Panel1: TPanel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Button1: TButton; DBEdit1: TDBEdit; DBEdit2: TDBEdit; DBEdit3: TDBEdit; DBEdit4: TDBEdit; Button2: TButton; TOPcount: TEdit; Label4: TLabel; Panel2: TPanel; procedure Button1Click(Sender: TObject); procedure DBGrid2DblClick(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TTestFunc = function : Boolean; TTestProc = procedure; var Form1: TForm1; //TestFunc: TTestFunc = nil; //TestProc: TTestProc; DllHandle: THandle; implementation {$R *.dfm} function TestFunc : Boolean; external 'ProjectDLL.dll' name 'TestFunc'; procedure TestProc; external 'ProjectDLL.dll' name 'TestFunc'; procedure TForm1.Button2Click(Sender: TObject); begin TestProc; end; procedure TForm1.DBGrid2DblClick(Sender: TObject); begin {with UnitDBM.Form2 do ShowMessage(ClientDataSet1.FieldByName('payment_date').AsString);} end; {initialization if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle > 0 then begin //@TestFunc := GetProcAddress(DllHandle, 'TestFunc'); DllHandle := LoadLibrary('ProjectDLL.dll'); End else begin MessageDlg('ProjectDLL.dll steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle);} end.
Delphi-Quellcode:
So für zwischendurch: Danke euch für die Hilfe! Ich konnte schon einiges lernen. :)
unit ProjectDLLInterface;
interface procedure TestProc; implementation function TestFunc : Boolean; external 'ProjectDLL.dll' name 'TestProc'; procedure TestProc; external 'ProjectDLL.dll' name 'TestProc'; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:17 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz