Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi DLL Init, Timer läuft nicht an (https://www.delphipraxis.net/150287-dll-init-timer-laeuft-nicht.html)

schwa226 12. Apr 2010 19:08


DLL Init, Timer läuft nicht an
 
Hi,

ich habe eine DLL gemacht, die beim Init eine Form erzeugt und einen Timer startet:
Delphi-Quellcode:
function InitDLL(Callback : TCallback):Boolean; stdcall;
begin
      try
        //plugin gets loaded, create Form
        if Not Assigned(frMain) then
          frMain := TfrMain.Create(NIL);

        frMain.AddLog('plugin got init');

        //start startupdelay
        frMain.StartStartUpDelay(StartDelay);

      finally
        Result := Assigned(frMain);
      end;
    end;
end;

procedure TfrMain.StartStartUpDelay(Interval:Integer);
begin
  //start startup delay
  StartUpDelay.Interval := Interval;
  StartUpDelay.Enabled := True;
end;
Wenn die DLL nun von eine Test-VCL Form von Delphi geladen wird und das Init aufgerufen wird, wird das Timer Event von StartUpDelay ausgelöst.

Wenn die DLL aber von einer C-Console-App (VS2008) geladen wird, wird das Timer Event nicht ausgelöst!?
Erst wenn ich die Form anzeige wird das Event ausgelöst:
Delphi-Quellcode:
procedure ShowForm();
begin
  if Assigned(frMain) then
  begin
    frMain.ShowModal;
  end;
end;
Sobald Showmodal aufgerufen wird spingt der Code in die StartUpDelay Timer Routine.

Woran kann das liegen?

himitsu 12. Apr 2010 19:28

Re: DLL Init, Timer läuft nicht an
 
Darum nutzt man keine VCL in einer DLL.

- der Timer wird über die VCL gesteuert
- in deiner DLL hast du keine Nachrichtenbehandlung (Windows-Messages) eingebaut
- die Nachrichtenschleife der EXE behandelt alle Nachichten und leitet sie an die DLL weiter
- eine C-EXE hat zwar (vermutlich) eine Nachrichtenschleife, aber diese behandelt garantiert keine Delphi-Ereignisse

Wenn unbedingt VCL in DLL,
- dann erstelle und behandle diese in einem eigenem Thread und arbeite in diesem Thread die Nachrichten ab
- und es darf keine Interation zwischen den beiden VCLs (EXE und DLL) geben, denn die VCL ist nicht threadsicher

SirThornberry 12. Apr 2010 19:50

Re: DLL Init, Timer läuft nicht an
 
Zitat:

Zitat von himitsu
Darum nutzt man keine VCL in einer DLL.

- der Timer wird über die VCL gesteuert
- in deiner DLL hast du keine Nachrichtenbehandlung (Windows-Messages) eingebaut
- die Nachrichtenschleife der EXE behandelt alle Nachichten und leitet sie an die DLL weiter
- eine C-EXE hat zwar (vermutlich) eine Nachrichtenschleife, aber diese behandelt garantiert keine Delphi-Ereignisse

Dann kläre ich mal auf.
- Es gibt in diesem Fall absolut nichts verwerfliches daran in diesem Fall die VCL in der DLL zu verwenden.
- Das der Timer über die VCL gesteuert wird ist nur bedingt richtig. Der Timer ist wohl Teil der VCL (je nach dem wie man VCL definiert) aber letztendlich wird er über das Windows-Nachrichtensystem gesteuert.
- Das die Nachrichtenschleife der Exe alle Nachrichten behandelt und diese an die DLL weiter leitet ist nur bedingt richtig. Eine Nachrichtenschleife behandelt alle Nachrichten des Threads in der die Schleife läuft. Da der Timer im Kontext des Hauptthreads der Exe erstellt wurde, werden die Nachrichten aller Fenster (und nichts anderes empfängt die Timernachrichten in der Timerklasse) dieses Threads, inklusive derer aus der DLL verarbeitet. Ebenso würde aber auch eine Nachrichtenschleife innerhalb der DLL die Nachrichten für die Fenster in der EXE verarbeiten sofern diese im gleichen Threadkontext laufen.
- Eine Nachrichtenschleife in einem C-Programm verarbeitet garantiert auch die Nachrichten welche für Fenster sind die aus Programmen/Programmteilen anderer programmiersprachlicher Herkunft sind.
Die Begründung warum es nicht funktioniert liegt hierin:
Zitat:

Zitat von schwa226
Wenn die DLL aber von einer C-Console-App (VS2008) geladen wird

Es handelt sich also um eine Konsolenanwendung wie sie auch mit Delphi erstellt werden kann. Und in einer Konsolenanwendung wird in der Regel keine Nachrichtenschleife verwendet weswegen die Nachrichten für den Timer nicht verarbeitet werden. Die verwendete Programmiersprache ist da völlig egal da das Nachrichtensystem auf Windows beruht und nichts spezifisches einer bestimmten Programmiersprache ist.

himitsu 12. Apr 2010 19:55

Re: DLL Init, Timer läuft nicht an
 
Es gibt aber auch eine Menge delphieigener Messages, welche direkt in Delphis Nachrichtenschleife behandelt werden
und Solche werden nicht von einer "fremden" Nachrichtenschleife behandelt.

SirThornberry 12. Apr 2010 19:58

Re: DLL Init, Timer läuft nicht an
 
Hast du dich mal mit Nachrichtenschleifen beschäftigt? Zumindest alle Punkt die ich von dir zitiert habe trafen in diesem konkreten Beispiel nicht zu. Und dem Fragesteller ging es nicht darum was allgemein irgendwann mal sein kann sondern er wollte wissen warum im konkreten Fall der Timer seinen Dienst nicht verrichtet. Und da waren die von dir genannten Punkte schlichtweg falsch.

Aber auch die letzte Aussage würde ich so nicht stehen lassen. Ich bin der Meinung (bin mir hier aber nicht zu 100% sicher) das nicht die Nachrichtenschleife spezielle Messages verarbeitet. Vielmehr holt die Nachrichtenschleife nur die Nachrichten aus der Nachrichtenwarteschlange ab und leitet diese durch den Aufruf von Windowsfunktionen an die entsprechende registrierten Nachrichtenfunktionen weiter.

So sieht übrigens eine Nachrichtenschleife in C aus:
Code:
while (GetMessage(&Message, NULL, 0,0))
{
    TranslateMessage(&Message);
    DispatchMessage(&Message);
}
In Delphi sieht sie übrigens nicht groß anders aus. Es werden die gleichen Funktionen aufgerufen. Rein der Syntax der Programmiersprache unterscheidet sich.

schwa226 12. Apr 2010 20:07

Re: DLL Init, Timer läuft nicht an
 
Danke euch beiden erst einmal!

Gibt es zu dem Thread/Message abarbeiten ein Beispiel.

Werde warscheinlich im Thread mit GetMessage ein Polling machen müssen und die WM_TIMER dann per PostMessage an mein HWND weiterleiten!?

himitsu 12. Apr 2010 20:07

Re: DLL Init, Timer läuft nicht an
 
Zitat:

Zitat von SirThornberry
In Delphi sieht sie übrigens nicht groß anders aus.

Bei NonVCL-Programmen schon, aber für die VCL ....

Delphi-Quellcode:
var
  Msg: TMsg;
begin
  while ProcessMessage(Msg) do {loop};



function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
  Handled: Boolean;
  Unicode: Boolean;
  MsgExists: Boolean;
begin
  Result := False;

  MsgExists := PeekMessage(Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);

  if MsgExists or PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
  begin
    Unicode := (Msg.hwnd = 0) or IsWindowUnicode(Msg.hwnd);

    if not MsgExists then
    begin
      if Unicode then
        MsgExists := PeekMessageW(Msg, 0, 0, 0, PM_REMOVE)
      else
        MsgExists := PeekMessageA(Msg, 0, 0, 0, PM_REMOVE);
    end;

    if MsgExists then
    begin
      Result := True;
      if Msg.Message <> WM_QUIT then
      begin
        Handled := False;
        if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
        if not IsPreProcessMessage(Msg) and not IsHintMsg(Msg) and
          not Handled and not IsMDIMsg(Msg) and
          not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
        begin
          TranslateMessage(Msg);
          if Unicode then
            DispatchMessageW(Msg)
          else
            DispatchMessageA(Msg);
        end;
      end
      else
      begin
  {$IF DEFINED(CLR)}
        if Assigned(FOnShutDown) then FOnShutDown(self);
        DoneApplication;
  {$IFEND}
        FTerminate := True;
      end;
    end;
  end;
end;

SirThornberry 12. Apr 2010 20:15

Re: DLL Init, Timer läuft nicht an
 
Sorry, aber auch da sehe ich keine wirkliche Sonderbehandlung. Es wird die Message lediglich für das Application-Object etc. bereit gestellt. Aber eine besondere Behandlung einzelner Messages sehe ich hier nicht. Aber das ist auch egal. Mir ging es nur darum einige Aussagen richtig zu stellen damit der Fragestellende nicht den Eindruck bekommt wirklich alles falsch gemacht zu haben wenn im konkreten Fall der einzige "Fehler" ist keine Nachrichtenschleife zu haben.

himitsu 12. Apr 2010 20:33

Re: DLL Init, Timer läuft nicht an
 
Für den Timer selber könnten diese Befehle entscheidend sein ... man weiß ja nicht was da intern noch alles passiert.
Delphi-Quellcode:
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
if not IsPreProcessMessage(Msg) and ...
  and not Handled
Und dann wird der Timer nicht einzeln verwaltet.
Ein Timer ohne Form/Owner muß nicht das Selbe sein, wie Einer mit Form/Owner ... hier kann es auch sein, daß schon bei dessen Erstellung etwas schief läuft, also z.B. wärend die Form erstellt/verwaltet wird.

Der Code vom TTimer selber ist noch relativ primitiv und dürfte so vermutlich auch in der C-Nachrichtenschleife behandelt werden, aber das TComponent hinter dem TTimer verbirgt 'ne Menge unberechenbaren VCL-Code.


Wie gesagt, der einfachste und sicherste Weg die VCL innerhalb einer "autonomen" DLL zu verwalten,
wäre diese VCL in einem separaten Thread und mit eigener Nachrichtenschleife laufen zu lassen.

schwa226 12. Apr 2010 21:27

Re: DLL Init, Timer läuft nicht an
 
Zitat:

Wie gesagt, der einfachste und sicherste Weg die VCL innerhalb einer "autonomen" DLL zu verwalten,
wäre diese VCL in einem separaten Thread und mit eigener Nachrichtenschleife laufen zu lassen.
Also beim laden der DLL einen Thread erzeugen, der dann die Form erzeugt?
Im Execute vom Thread dann wie am besten die Nachrichten abarbeiten?

Tut leid, aber ich steh momentan voll auf dem Schlauch... :roll:

Danke!


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:11 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz