Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   DLL neu starten nach beenden (https://www.delphipraxis.net/155362-dll-neu-starten-nach-beenden.html)

EWeiss 20. Okt 2010 13:21

DLL neu starten nach beenden
 
Ich habe eine Vis geschrieben mit 3 Modulen
Winamp stellt die möglichkeit zur verfügung die Module über einen Button vor, zurück oder zufällig zu starten.
Mein problem ist nur wenn ich ein Modul beendet habe kann ich kein neues innerhalb der DLL auswählen
weil sich diese dadurch beendet.

Ich muss quasi die Module1_Quit aufrufen zum beenden
Delphi-Quellcode:
procedure _Cover_Quit(This_Mod: PWinAMPVisModule); cdecl;
um danach das neue mit
Module1_Init zu aktivieren.

Nur wie stelle ich das an wenn die DLL dadurch beendet wird?

In einer Anwendung kann ich ja unterbinden das sie doppelt gestartet wird
Delphi-Quellcode:
initialization
  hMutex := CreateMutex(nil, True, 'Global\Soundmachine');
  if GetLastError = ERROR_ALREADY_EXISTS then
    Halt;

finalization
  if hMutex <> 0 then
    CloseHandle(hMutex)
Gibt es sowas ähnliches damit sich meine DLL selbst wieder aufruft bzw.. gar nicht erst beendet?

Ich hoffe ihr versteht was ich damit meine.

gruss

ele 20. Okt 2010 15:54

AW: DLL neu starten nach beenden
 
Meines Wissens geht das nicht. Wenn WinAmp FreeLibrary aufruft gibt es nichts das deine DLL dagegen machen kann. Aber du kannst durchaus experimentieren. Der folgende Code erlaubt es dir beim Laden bzw. Entladen der DLL code auszuführen (am Ende der DLL einfügen):

Delphi-Quellcode:
procedure DLLEntryPoint(Reason: Integer);
begin
  case Reason of
    DLL_PROCESS_ATTACH:
      Load; // wird ausgeführt beim laden der DLL
    DLL_PROCESS_DETACH:
      Unload; // wird ausgeführt beim entladen der DLL
  end;
end;

begin
  DllProc := @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Die Prozeduren Load und Unload musst du natürlich noch implementieren.

EWeiss 20. Okt 2010 18:29

AW: DLL neu starten nach beenden
 
Zitat:

Zitat von ele (Beitrag 1056753)
Meines Wissens geht das nicht. Wenn WinAmp FreeLibrary aufruft gibt es nichts das deine DLL dagegen machen kann. Aber du kannst durchaus experimentieren. Der folgende Code erlaubt es dir beim Laden bzw. Entladen der DLL code auszuführen (am Ende der DLL einfügen):

Delphi-Quellcode:
procedure DLLEntryPoint(Reason: Integer);
begin
  case Reason of
    DLL_PROCESS_ATTACH:
      Load; // wird ausgeführt beim laden der DLL
    DLL_PROCESS_DETACH:
      Unload; // wird ausgeführt beim entladen der DLL
  end;
end;

begin
  DllProc := @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Die Prozeduren Load und Unload musst du natürlich noch implementieren.

Du weist schon das eine Winamp DLL so ausschaut ?

Delphi-Quellcode:
function winampVisGetHeader: PWinAMPVisHeader; cdecl;
begin
  result := @VisHeader;
end;

exports
  winampVisGetHeader;

begin
Ich wüßte jetzt nicht was du denkst das ich bei Load verwenden könnte.

gruss

ele 20. Okt 2010 20:01

AW: DLL neu starten nach beenden
 
Das funktioniert bei jeder DLL, nicht bloss bei WinAmp. Damit kann man einfach code beim laden oder entladen der DLL ausführen. Ich wüsste allerdings nicht wie man das entladen abbrechen könnte. Du könntest vielleicht versuchen beim Unload eine Exception zu werfen, aber ich hab keine Ahnung wie das System bzw. WinAmp darauf reagiert.

Und das mit dem selbst wieder aufrufen... ich glaube nicht das das aus der DLL aus geht - im Gegenteil, die Gefahr besteht, dass sich die DLL rekursiv immer wieder lädt bis dem System die Ressourcen ausgehen (Stackoverflow oder noch schlimmeres).

Aber möglicherweise verstehe ich die Problematik auch nicht ganz. Was genau heisst "Vis mit 3 Modulen"? Ich meine ich kenne Winamp und ich habe auch schon mit den Visualisierungen herumgespielt (als Anwender nicht als Programmierer), aber irgendwie verstehe ich nicht ganz was du versuchst zu erreichen. Das umschalten der Module macht doch WinAmp, warum möchtest du da reinfummeln?

EWeiss 20. Okt 2010 20:26

AW: DLL neu starten nach beenden
 
Zitat:

Zitat von ele (Beitrag 1056805)
warum möchtest du da reinfummeln?

Weil Winamp eine möglichkeit zur verfügung stellt wie oben beschrieben
die Module bzw.. Presets vor ,zurück und als Random auszuführen.
Ich denke mal nicht das ich da rumfummel wenn die API von Winamp dafür zur verfügung gestellt wird.

Diese Funktion von Winamp habe ich ja schon in meinem wrapper umgesetzt
jetzt möchte ich natürlich auch mein eigenes Plugin den gegebenheiten anpassen was nur logisch ist.

Ok wenn es nicht machbar ist werde ich die Module wohl zusammenführen müssen und diese innerhalb eines Moduls ausführen.

gruss Emil

Siehe Button unter dem VisWindow im Anhang(Bild)

Assarbad 4. Nov 2010 03:03

AW: DLL neu starten nach beenden
 
Zitat:

Zitat von ele (Beitrag 1056805)
Das funktioniert bei jeder DLL, nicht bloss bei WinAmp. Damit kann man einfach code beim laden oder entladen der DLL ausführen.

Sorry, aber ich muß mich hier nochmal klugscheißerisch betätigen.

Einfach ausführen ist Quark. Der Grund ist, daß in der DllMain grundsätzlich das Loader-Lock gehalten wird. Man kann also gewisse Sachen absolut nicht machen. Manche gehen eventuell gut (auch wenn nicht erlaubt), aber das ("dynamische") Laden einer anderen DLL ist bspw. tabu.

Zitat:

Zitat von ele (Beitrag 1056805)
Ich wüsste allerdings nicht wie man das entladen abbrechen könnte.

Kann man nicht. Man kann es aber verhindern. DLLs haben im Speicher einen Referenzzähler. Gut, eigentlich haben sie ein Handle, welches ein darunterliegendes Kernelobjekt hat welches den Zähler hat ... Fällt der auf Null, wird die DLL endgültig entladen. Rein theoretisch könnte Code in deiner DLL einfach auf sich selber nochmal LoadLibrary() aufrufen (nur eben nicht in DllMain) ... damit hast du eine Referenz mehr als Winamp kennt. Entsprechend wird deine DLL nicht entladen werden (wenn wir annehmen, daß Winamp nicht einfach solange FreeLibrary aufruft bis deine DLL wirklich wech ist). Allerdings habe ich es nicht getestet, sondern es basiert auf dem Grundlagenwissen zu DLLs usw. und ich halte es für gangbar ...

Zitat:

Zitat von ele (Beitrag 1056805)
Du könntest vielleicht versuchen beim Unload eine Exception zu werfen, aber ich hab keine Ahnung wie das System bzw. WinAmp darauf reagiert.

Scherz? Ganz schlechter, wenn es einer war. Denn Exceptions sind, insofern wir nicht von SEH reden, eine Compilerangelegenheit. Und man mag es kaum glauben, aber Winamp dürfte kaum eine Ahnung von Delphis Exceptions haben. Ja, mir ist bekannt, daß viele Compiler auf Windows SEH als Mechanismus für Sprach-Exceptions benutzen. Aber das berührt das vorgesagte nicht im Geringsten. Ich bin mir sogar relativ sicher, daß Winamp SEH-Exceptions abfängt (weil ich die Option zum Abschalten dieser Funktion gesehen habe), aber das kann auch schiefgehen. Grundsätzlich hat sich ein Plugin an die Regeln des ausführenden Programms zu halten!

Zitat:

Zitat von ele (Beitrag 1056805)
Und das mit dem selbst wieder aufrufen... ich glaube nicht das das aus der DLL aus geht - im Gegenteil, die Gefahr besteht, dass sich die DLL rekursiv immer wieder lädt bis dem System die Ressourcen ausgehen (Stackoverflow oder noch schlimmeres).

Unsinn. Siehe oben. Da die DLL in Winamp ist und beim Laden einer weiteren Instanz von sich selbst exakt den selben Speicher belegt den sie ohnehin schon hat, kann man bspw. eine einfache Variable per Interlocked-Funktionen hochzählen lassen und bpsw. ab einem bestimmten Wert, ich sage mal 1 oder 2, nicht mehr LoadLibrary aufrufen.

ele 4. Nov 2010 14:48

AW: DLL neu starten nach beenden
 
Zitat:

Einfach ausführen ist Quark. Der Grund ist, daß in der DllMain grundsätzlich das Loader-Lock gehalten wird. Man kann also gewisse Sachen absolut nicht machen. Manche gehen eventuell gut (auch wenn nicht erlaubt), aber das ("dynamische") Laden einer anderen DLL ist bspw. tabu.
Da wiederspreche ich auch nicht.

Zitat:

Kann man nicht. Man kann es aber verhindern. DLLs haben im Speicher einen Referenzzähler. Gut, eigentlich haben sie ein Handle, welches ein darunterliegendes Kernelobjekt hat welches den Zähler hat ... Fällt der auf Null, wird die DLL endgültig entladen. Rein theoretisch könnte Code in deiner DLL einfach auf sich selber nochmal LoadLibrary() aufrufen (nur eben nicht in DllMain) ... damit hast du eine Referenz mehr als Winamp kennt. Entsprechend wird deine DLL nicht entladen werden (wenn wir annehmen, daß Winamp nicht einfach solange FreeLibrary aufruft bis deine DLL wirklich wech ist). Allerdings habe ich es nicht getestet, sondern es basiert auf dem Grundlagenwissen zu DLLs usw. und ich halte es für gangbar ...
Ja durchaus denkbar, dass es so funktioniert. Aber die Frage ist wie WinAmp wiederum darauf reagiert wenn eine DLL nicht sauber entladen wird bei einem FreeLibrary. Da kann ich mir allerlei Folgefehler ausmalen...

Zitat:

Scherz? Ganz schlechter, wenn es einer war. Denn Exceptions sind, insofern wir nicht von SEH reden, eine Compilerangelegenheit. Und man mag es kaum glauben, aber Winamp dürfte kaum eine Ahnung von Delphis Exceptions haben. Ja, mir ist bekannt, daß viele Compiler auf Windows SEH als Mechanismus für Sprach-Exceptions benutzen. Aber das berührt das vorgesagte nicht im Geringsten. Ich bin mir sogar relativ sicher, daß Winamp SEH-Exceptions abfängt (weil ich die Option zum Abschalten dieser Funktion gesehen habe), aber das kann auch schiefgehen. Grundsätzlich hat sich ein Plugin an die Regeln des ausführenden Programms zu halten!
Ich habe keine systemnahe Kenntnisse von Exceptions. Ich verwende die Dinger einfach und ich weiss dass das auch über die DLL-Grenze hinweg funktioniert. Wie das mit der Kompatibilität unter den einzelnen Programmiersprachen aussieht weiss ich nicht. Deshalb habe ich ja auch geschrieben, dass er es versuchen soll, wenn ich mir sicher gewsen wäre es funktioniert (oder eben nicht) hätte ich das auch so geschrieben.

Zitat:

Unsinn. Siehe oben. Da die DLL in Winamp ist und beim Laden einer weiteren Instanz von sich selbst exakt den selben Speicher belegt den sie ohnehin schon hat, kann man bspw. eine einfache Variable per Interlocked-Funktionen hochzählen lassen und bpsw. ab einem bestimmten Wert, ich sage mal 1 oder 2, nicht mehr LoadLibrary aufrufen.
Ja und was wenn man eben keine Variable hochzählt? Ich glaube die Auswirkungen auf das System könnten vo der übleren Sorte sein... Deshalb habe ich auch auf die Gefahr aufmerksam machen wollen. Ich sage nicht dass es nicht möglich ist, ich weiss dass man von einer DLL aus andere DLLs dynamisch laden kann (das man das nicht von DLLMain aus mahcen soll/kann sei mal dahingestellt). Aber man sollte auch entsprechend vorsichtig sein...

Assarbad 4. Nov 2010 15:30

AW: DLL neu starten nach beenden
 
Zitat:

Zitat von ele (Beitrag 1059645)
Ja durchaus denkbar, dass es so funktioniert. Aber die Frage ist wie WinAmp wiederum darauf reagiert wenn eine DLL nicht sauber entladen wird bei einem FreeLibrary. Da kann ich mir allerlei Folgefehler ausmalen...

Okay, dann male mal. Wir halten einfach den Referenzzähler größer als Null. Winamp ruft einfach FreeLibrary auf, was genau sollte da fehlschlagen? ;) ... es setzt doch nur den Zähler um eins runter ...

Zitat:

Zitat von ele (Beitrag 1059645)
Ja und was wenn man eben keine Variable hochzählt? Ich glaube die Auswirkungen auf das System könnten vo der übleren Sorte sein... Deshalb habe ich auch auf die Gefahr aufmerksam machen wollen. Ich sage nicht dass es nicht möglich ist, ich weiss dass man von einer DLL aus andere DLLs dynamisch laden kann (das man das nicht von DLLMain aus mahcen soll/kann sei mal dahingestellt). Aber man sollte auch entsprechend vorsichtig sein...

Stimmt. Deshalb sollte man es mit Zähler machen - und threadsicher. Allerdings nehme ich an, daß die exportierten Funktionen selber vielleicht nichtmal so oft aufgerufen werden. Und wenn man da drin LoadLibrary aufruft, muß man auch sehr sehr lange Arbeiten bis der Referenzzähler von 32bit überläuft :zwinker:

ele 4. Nov 2010 16:12

AW: DLL neu starten nach beenden
 
Malen ist einfach: Ich kenne das nicht genau bei WinAmp, aber ich habe bei meinem eigen Projekt folgendes festestellt:

Mein Projekt lädt die Plugin-DLLs und ruft dort eine Init-Funktion auf, die mir ein Interface zurückliefert mit dem ich dann auf die DLL-funktinen zugreifen kann. In dieser Init-Funktion werden Klassen registriert, ganz einfach in einer Sortierten StringListe (ist eine Globale Variable - ich weiss dass das nicht toll ist, geht aber nicht anders).

Wenn nun die DLL nicht sauber entladen wird, schlägt das Ausführen der Init-Funktion beim nächsten mal fehl, weil die entsprechenden Klassen schon einmal registriert wurden.

Solche Szenarien sind durchaus auch bei WinAmp oder ähnlichen Problemstellungen denkbar...

Assarbad 4. Nov 2010 16:45

AW: DLL neu starten nach beenden
 
Zitat:

Zitat von ele (Beitrag 1059679)
Solche Szenarien sind durchaus auch bei WinAmp oder ähnlichen Problemstellungen denkbar...

In der Tat, ein berechtigter Einwand. Statische Variablen sind aber einfach nur eine Form der globalen Variablen, die man ohnehin vermeiden sollte ;)

Aber hast schon recht, so ein Szenario würde ggf. fehlschlagen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:43 Uhr.
Seite 1 von 2  1 2      

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