2017-03-14 1 views
0

Ich habe ein Problem, und ich habe versucht, eine Lösung zu suchen, kann aber nicht erreichen, was ich will. Tut mir leid, wenn das wirklich einfach ist, bitte zeigen Sie mir einfach, wie Sie es richtig machen.VCL/LCL - ein Formular in der DLL - keine Anwendung Taskleiste Fenster, kann das Hauptformular nicht minimieren

Also! Ich habe ein C-Programm, das ein Loader ist. Es muss meine DLL in Delphi oder Lazarus (Free Pascal) geschrieben aufrufen. Die DLL ist eigentlich eine Standalone-GUI-Anwendung: Während des Debuggens kompiliere ich sie bedingt als EXE und es funktioniert.

Mein Build-Skript kompiliert es als DLL mit einem Einstiegspunkt, der es ausführen muss, so wie es eigenständig funktioniert. Ich erwarte genau dasselbe Verhalten, aber ich kann bei Bedarf verschiedene Dinge tun (insbesondere das Anwendungssymbol einstellen).

Loader ist ein Konsolen-Stil-Programm, aber kompiliert ohne eine Konsole - keine Fenster, nichts. Es lädt nur DLL und ruft eine Funktion auf.

Problem ist, dass, wenn ich sogar leere Standard-Projekt mit einem Formular als EXE erstellen - es wird tatsächlich "Master" Anwendung (.Handle <> 0) Fenster in der Taskleiste haben. So kann ich seinen Titel unabhängig von der Hauptformularbeschreibung festlegen.

Aber wenn das gleiche in einer DLL ist - es gibt kein Anwendungsfenster (.Handle = 0), der Titel wird die Formularüberschrift sein, aber der wichtigste Fehler: ein Formular kann nicht minimiert werden!

In Delphi 7 geht es Hintergrund unter anderen Fenstern (aber Taskleiste bleibt!); in Lazarus minimiert es sich einfach ins Nirgendwo (verdeckt, keine Möglichkeit mehr zu restaurieren); beides ohne jegliche Minimierung der Animation.

Ansonsten scheint sich meine Anwendung normal zu verhalten. Das ist nur ein Problem, das ich habe.

OK, ich weiß, dass Formen in Bibliotheken ist eine schlechte Sache zu tun, aber: „eine andere“ VCL völlig unabhängig vom Host-Instanz zu instanziiert, vielleicht sogar in anderen Thread

  1. Mir geht es gut.

  2. Es gibt keine VCL in meiner bestimmten Host-Anwendung! Für mich muss es funktionieren genau so, wie es wird in EXE allein ...

Ich suchte etwas über Application.Handle in DLL, und jetzt verstehen, als ich einen Griff passieren müssen, um die Host-Anwendungsobjekt, so DLL wird mit anderen Host-Formen verbunden, aber ich habe keine! Es ist sogar nicht Delphi ... (und Anwendung: = TApplication.Create (nil); auch nicht half)

Alles, was von folgenden wird mir wahrscheinlich helfen:

  • A) Wie VCL anweisen, zu erstellen ein normales Anwendungsobjekt für mich? Wie kann es passieren, dass ich in EXE diesen Code kopieren kann?

  • B) Wie erstelle ich ein passendes Hauptfenster von C (richtige Stile, etc.), um es an DLL übergeben? Außerdem glaube ich, dass es in Free Pascal keinen direkten Zugriff auf den TApplication-Handle-Wert gibt, sodass ich ihn wahrscheinlich nicht zuordnen konnte.

  • C) Wie ohne ein Taskbar-Fenster zu leben, aber habe meine Form (gute Nachricht: mein Programm hat nur ein Formular!), Um richtig zu minimieren (oder nur irgendwie ...)?

ich Sie jetzt alle lieben einen Code, um zu sehen, so ist es hier:

// default empty project code, produces valid working EXE: 
program Project1; 

uses Forms, Unit1 in 'Unit1.pas' {Form1}; 
{$R *.res} 

begin 
    Application.Initialize; 
    Application.CreateForm(TForm1, Form1); 
    Application.Run; 
end. 

+

// that's how I tried to put it in a DLL: 
library Project1; 

uses Forms, Unit1 in 'Unit1.pas' {Form1}; 
{$R *.res} 

function entry(a, b, c, d: Integer): Integer; stdcall; 
begin 
    Application.Initialize; 
    Application.CreateForm(TForm1, Form1); 
    Application.Run; 
    Result := 0; 
end; 

exports 
    entry; 

begin 
end. 

I Funktion speziell gestaltete Eintrag() mit rundll32 aufrufbar zu sein, nur zum Testen.

Auch habe ich versucht, den Körper direkt auf "begin end." Initialisierung Abschnitt - das gleiche falsche Verhalten.

// To call a DLL, this can be used: 
program Project1; 

function entry(a, b, c, d: Integer): Integer; stdcall; external 'Project1.dll'; 

begin 
    entry(0, 0, 0, 0); 
end. 

Auch CMD-Befehl "rundll32 project1.dll entry" wird es sofort ausgeführt werden. (Ja, so könnte ich einen Griff bekommen, den Rundll mir gibt, aber es ist sowieso nicht was ich will.)

Letzte Anmerkungen: (a) die DLL muss in Lazarus kompiliert werden; Eigentlich dachte ich zuerst, dass es ein Fehler in LCL ist, aber jetzt, wenn ich in Delphi7 getestet habe, sehe ich das gleiche; und da der Delphi-Fall einfacher und robuster ist, habe ich beschlossen, das hier zu machen; (b) Mein C-Loader ruft LoadLibrary nicht auf, er benutzt TFakeDLL-Hack (diese OBJ-Datei wurde optimiert, um ohne Delphi-Wrapper zu funktionieren) und lädt meine DLL aus dem Speicher (so habe ich kein Handle für DLL selbst), aber ansonsten Ihr Verhalten ist das gleiche.

+2

Ich habe Formulare in Dlls in meiner D3-Zeit für gängige Dienstprogramme verwendet und bin auch in der Lage, unabhängig von einer ausführbaren Datei zu laufen, die eine einzige Zeile enthält, die Ihrer Konfiguration sehr ähnlich ist. Habe nicht mit der Anwendung oder irgendetwas getüftelt, nur ShowModal verwendet, um das Formular zu starten, das die erforderliche Nachrichtenschleife ausführt. Natürlich gibt es keine Modalität, da es keine anderen Formen gibt. Ich erinnere mich nicht an irgendwelche Komplikationen mit den Formen, sie haben einfach normal gehandelt. –

+0

@ David Heffernan, hallo! (Erinnere dich an mich? ^^). Warum andere Tags entfernen? Ich denke zumindest "Delphi" ist notwendig, da dieses Problem auch in Delphi DLL einfach ist. Kann ich [Delphi] zurück hinzufügen? – aleksusklim

+0

@Sertac Akyuz, danke! Ich habe meine eigene Antwort basierend auf Ihrer Lösung hinzugefügt. – aleksusklim

Antwort

1

Okay, dank @Sertac Akyuz, habe ich versucht, mit .ShowModal:

// working Delphi solution: 
library Project1; 

uses Forms, Dialogs, SysUtils, Unit1 in 'Unit1.pas' {Form1}; 
{$R *.res} 

function entry(a, b, c, d: Integer): Integer; stdcall; 
begin 
    Result := 0; 
    Application.Initialize; 
    Form1 := TForm1.Create(nil); 
    try 
    Form1.ShowModal; 
    except 
    on e: Exception do 
     ShowMessage(e.message); 
    end; 
    Form1.Free; 
end; 

exports 
    entry; 

begin 
end. 

Es gibt noch kein Programmfenster (Task-Leiste Titel gleich Beschriftung bilden), aber jetzt kann meine Form erfolgreich (mit System minimiert werden Animation). Beachten Sie, dass ich für die EXE-Kompilierung standardmäßig mit der Anwendung arbeiten muss, denn als ich versuchte, das Formular so zu erstellen, begann es auf dem Desktop zu minimieren (Iconify) anstatt auf der Taskleiste.

Es funktioniert perfekt in leeren Standard-Lazarus-Projekt zu. Aber als ich versuchte, es in mein Produktionsprogramm zu implementieren, gab es mir "Disk Full" -Ausnahme bei .ShowModal!

Das Ding hat mich etwas früher frustriert (und deshalb habe ich Modalität ganz losgeworden, habe es nicht mehr versucht), aber jetzt war ich entschlossen genug, um das Fundament zu haben.

Und ich habe das Problem gefunden! Mein Build-Skript übergibt die Compileroption "-WG" ("Grafikanwendung angeben") nicht. Sieht so aus, als ob etwas in LCL den konsolenähnlichen Modus verwendet und die Modality-Schleife aus irgendeinem Grund fehlgeschlagen ist.

Dann hatte ich ein anderes sehr verwirrendes Problem, das ich teilen möchte. OnCreate meines Formulars war ziemlich groß und komplex (sogar das Starten anderer Threads), und einige interne Funktionen geben mir Zugriffsverletzung, wenn versucht wird, einige Sachen mit einem der Steuerelemente auf dem Formular zu tun. Es sah aus wie die Steuerung noch nicht aufgebaut ist, oder die Form selbst ...

Es stellt sich heraus, dass der tatsächliche Anruf Form1:=TForm1.Create(nil); offensichtlich wird die globale Variable „Form1“ unassigned während Formcreate Veranstaltung verlassen. Die Lösung war einfach: Form1:=Self; am Anfang der TForm1.FormCreate(Sender: TObject);

hinzufügen Jetzt funktioniert alles ohne Probleme.Ich kann auch andere Formen mit einer normalen Form2.Show(); verwenden, wenn ich zuerst sie zu meinem Eintrag hinzufügen() Funktion, wie Form2:=TForm2.Create(Form1);

(edit: minor Notiz, wenn Sie Lazarus verwenden würden und versuchen Eintrag() Funktion von jedem anders laufen Thread als einer, der DLL-Bibliothek selbst geladen - dann sollten Sie setzen MainThreadID:=GetCurrentThreadId(); nur über Application.Initialize;)

Yay, diese Frage ist gelöst!

Verwandte Themen