Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Probleme mit Bildschirmschonervorschau (https://www.delphipraxis.net/103569-probleme-mit-bildschirmschonervorschau.html)

Popov 17. Nov 2007 18:54


Probleme mit Bildschirmschonervorschau
 
Ich hab meine Glaskugel gerade in der Reparatur, also wende ich mich an euch, denn mir fällt keine Antwort auf die Frage ein und ich sehe keinen Fehler.

Es geht um einen Bildschirmschoner. Ich hab in meinem Leben unzählige Bildschirmschoner programmiert. Der Letzte liegt zwar schon sechs Monate zurück, aber die Technik habe ich drauf, d.h. ich weiß an was man alles denken muß. Irgendwann habe ich mich ausführlich informiert und verstehe alles was zum Bildschirmschoner dazugehört.

Nun habe ich ein Stück älteren Code für eine Animation wiedergefunden und dachte mir draus einen Bildschirmschoner zu machen. Soweit ist alles fertig und soweit ich es überblicken kann (mehrfach kontrolliert) hat der Code keinen Fehler.

Das Problem ist folgendes: wenn ich das Dialogfenster Eigenschaften von Anzeige aufrufe und dann im Register Bildschirmschoner meinen Bildschirmschoner aufrufe, erscheint im Vorschaufenster mein Bildschirmschoner. Unten in der Taskleiste erscheint zu diesem Zeitpunkt mein Programm, aber das ist Absicht. An dieser Stelle habe ich das aus einem bestimmten Grund noch nicht stillgelegt. Also wie gesagt erscheint im Vorschaufenster mein Bildschirmschoner. Schließe ich jetzt die Vorschau, bleibt das Programm offen. In der Regel sollte es geschlossen werden. Wenn ich die Vorschau ein weiteres mal öffne, wird ein weiteres Programm geöffnet und nicht geschlossen. So oft ich das Programm öffne, so viele Programme habe ich in der Taskleiste die nicht wieder geschlossen werden. Die Programme sind auch im Task-Fenster zu sehen. Das gleiche gilt für die Vorschau. Programme werden geöffnet, aber nicht geschlossen. Sogar bei der Configuration bleibt das Programm bestehen.

Wie sieht es in der Delphiumgebung aus? Hier habe ich keine Probleme. Auch habe ich keine Probleme wenn ich das Programm aus dem Explorer öffne. Bildschirmschoner werden geschlossen und hinterlassen keine Rückstände. Also Frage ich mich wie es mit den alten Bildschirmschonern aussieht. Keiner hinterlässt etwas in der Taskleiste oder im Tast-Fenster. Der jetztige BS ist der einziege mit dem Problem.

Also habe ich das ganze Programm nochmals überprüft. Eigentlich ist die ganze Canvas Routine in einer extra Unit ausgelagert, so daß im Mainfenster (je nachdem welches es mal ist, denn beim BS kann es mal das oder das sein) so gut wie nichts. Das sind nur Routinen für Mausbewegung, BS im System an oder abmelden usw. Kein Code der sonderbar wäre. Aber auch wenn, ich hab insgesammt drei Mainfenster, je nach Zweck. Neben dem Hauptfenster für die Animation, habe ich noch das Prieview Fenser. Aber auch wenn das wegen seiner Ähnlichkeit zum Hauptfenser verdächtig ist, so gibt es noch das Konfigurationsfenster. Dort findet sich bis auf paar Zugriffe auf die INI nichts. Es kann also nichts das Programm beim Beenden hindern.

Also eventuell die Projektdatei? Hier habe ich eigentlich den gleichen Code den ich auch in anderen Bildschirmschonern benutze. Auch nichts besonderes. Um das ganze noch verwirrender zu machen, habe ich eine komplett leere Version in der alles entfernt wurde bis auf leere Fenseter.

Wie man sieht ist das Problem nicht einfach. Im Programm ist nichts was ich nicht schon mal in irgendeinem anderen BS so gemacht habe. Nichts ist neu und zum ersten Mal so programmiert. Was hindert also den BS sich wieder zu schließen wenn ich ihn über Eigenschaften von Anzeige aufrufe, sonst aber doch?

[edit=Luckie]Threadtitel geändert. Mfg, Luckie[/edit]

alzaimar 17. Nov 2007 19:23

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Kommentiere einfach sukkzessive immer mehr Code aus, bis das Problem verschwindet.

Oder fange mit dem Rumpfprogramm an, das sich normal verhalten sollte und packe sukkzessive immer mehr Code hinzu, bis das Problem auftritt.

Popov 17. Nov 2007 19:59

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Liste der Anhänge anzeigen (Anzahl: 1)
Auch wenn ich es nicht sonderlich betont habe, aber es steht schon im ersten Text: ich habe eine Kopie des BS in dem fast alles weg ist und der BS auf das nötigste reduziert ist. Noch mehr auskommentieren kann man nicht, da dann der BS nicht mehr als BS korrekt funktionieren würde. Ich hab sogar einige wenige wichtige BS Funktionen gelöscht.

Am besten ich uppe den Code rauf.

Entpacken, kompilieren und im Explorer über Kontextmenü installieren. Es öffnet sich automatisch das Bildschirmschoner Einstellfenster. Dann unten die Taskleiste beobachten ob beim Schließen auch das Programm beendet wird.

SirThornberry 17. Nov 2007 20:06

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
meine Vermutung wäre das dein Programm in einer Schleife festhängt. Also das du ständig das Bild aktuallisierst und mit Application.Processmessages dafür sorgst das nachrichten verarbeitet werden. Dadurch das es in einer schleife geschieht kann das Programm jedoch nicht entladen werden. Das wäre meine Vermutung. Aber meine Glaskugel war noch nie die beste.

Popov 17. Nov 2007 20:30

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Nein, keine Schleifen, keine Messages, nichts. Im Zweifelsfall gibt es noch das Config-Fenster das nur zwei leere Prozeduren mit Close Anweisung enthält.

Popov 17. Nov 2007 22:09

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Also ich hab noch ein wenig experimentiert und weiß jetzt etwas mehr. Entgegen dem was ich zuerst geschrieben habe, daß auch das Hauptfenster und Konfiguration-Fenster nicht beendet werden, stellte sich heraus, daß beide durchaus beendet werden. Allerdings wird nach dem Beenden eines der beiden Fenster in Eigenschaften von Anzeige der Screensaver erneut mit dem /P Parameter für das Previev gestartet. Es sah also nur so aus als ob das Hauptfenster oder Konfiguration-Fenster nicht beenden würde.

Der Schuldige Part ist also Preview.

Also hab ich alzaimar Empfehlung bis ins Extreme getrieben und hab alles bis auf das Preview Fenster gelöscht. Sogar die Projektdatei hat keinen Extracode.

Delphi-Quellcode:
uses
  SysUtils,
  Forms,
  uPreview in 'uPreview.pas' {Preview};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TPreview, Preview);
  Application.Run;
end.
Das Previefenster hat nur noch eine Prozedur:

Delphi-Quellcode:
procedure TPreview.FormCreate(Sender: TObject);
var
  hWnd: THandle;
  Rec: TRect;
begin
  hWnd := StrToIntDef(ParamStr(2), 0);
  GetWindowRect(hWnd, Rec);
  SetBounds(0, 0, Rec.Right - Rec.Left, Rec.Bottom - Rec.Top);

  BorderStyle := bsNone;

  Windows.SetParent(Self.Handle, hWnd);
end;
Noch weniger geht nicht. Das Ganze wird korrekt im Preview Monitor angezeigt, nur nicht beendet. So in etwa, zumindest den zweiten Code, habe ich in jeder meiner BS. Keine Ahnung was hier anders ist.

SirThornberry 18. Nov 2007 06:50

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
hast du exakt den gleichen Quelltext auch bei den anderen Bildschirmschonern?
Meine aktuelle Vermutung: Dein Bildschirmschoner wird gestartet und später wird versucht, über das Handle welches beim Starten deines Bildschirms aktuell, das Programm zu beenden. Durch das umsetzen des BorderStyle kann es aber passieren dass, das Hauptfenster neu kreiert wird und somit dann ein anderes Handle hat. Funktioniert es wenn du den Borderstyle gleich in der DFM auf bsNone setzt?

alzaimar 18. Nov 2007 07:31

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Gut vermutet ...
Delphi-Quellcode:
procedure TCustomForm.SetBorderStyle(Value: TFormBorderStyle);
begin
  if FBorderStyle <> Value then
  begin
    FBorderStyle := Value;
    AutoScroll := FBorderStyle in [bsSizeable, bsSizeToolWin];
    if not (csDesigning in ComponentState) then RecreateWnd; // <<-- Möööööp
  end;
end;
Zitat:

Zitat von Popov
Also hab ich alzaimar Empfehlung bis ins Extreme getrieben und hab alles bis auf das Preview Fenster gelöscht. Sogar die Projektdatei hat keinen Extracode.
...
Noch weniger geht nicht....

Hinterher ist man immer schlauer (ist nicht ironisch gemeint): Noch weniger geht doch. Denn man hätte auch den Code im Preview noch ausklammern können ... Ich hätte das vermutlich auch nicht auskommentiert, aber in Zukunft schon. (Klingt aber echt nach Klugscheisser, soll's aber nicht sein)

Ich denk mir immer (bildlich gesehen), das selbst ein Semikolon irgendeinen Schmonz verursachen kann. Man kann gar nicht so blöd denken, wie's dann kommt.

hathor 18. Nov 2007 10:07

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Liste der Anhänge anzeigen (Anzahl: 2)
Betrifft Directive - So geht's:

Delphi-Quellcode:
program NurTest;

{$E scr} // Erstellt Programm mit .scr Endung

uses
  SysUtils,
  Forms,
  uMain in 'uMain.pas' {Screensaver},
  uOptions in 'uOptions.pas' {Options},
  uPreview in 'uPreview.pas' {Preview};

{$R *.RES}
{$D SCRNSAVE : Test Screen Saver}
var
  Param1: String;
  Param1Chr: Char;
...
Offensichtlich darf bei meinem DELPHI 2007 diese Directive erst NACH der $R-Directive
auftauchen. Im Übrigen sieht man sie nur mit geeigneten Programmen, z.B. Hexeditor.
Siehe Anhänge.

DP-Maintenance 18. Nov 2007 10:15

DP-Maintenance
 
Dieses Thema wurde von "Matze" von "Programmieren allgemein" nach "Multimedia" verschoben.
Delphi-Frage

Popov 18. Nov 2007 10:17

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Ok, ich hab das Problem gefunden. Wie ich schon oben geschrieben habe liegt mein letzter Bildschirmschoner schon über ein halbes Jahr her, oder länger. Deshalb hab ich die eine oder andere Sache schon mal vergessen, und kein Bildschirmschoner ist gleich wie die anderen. Manchmal muß man nur etwas über das Problem quatschen um selbst auf die Lösung zu kommen, denn dabei denkt man oft an Sachen die man vorher nicht beachtet hat.

Der schuldige Part ist der hier:

Delphi-Quellcode:
OldStyle := GetWindowLong(Handle, GWL_STYLE);
SetWindowLong(Handle, GWL_STYLE, (OldStyle and not WS_POPUP) or WS_CHILD or WS_VISIBLE);
Ich hab die zwei Zeilen nicht vergessen, aber ihre Bedeutung nicht mehr im Kopf gehabt. Außerdem habe ich die Reihenfolge falsch gesetzt, so daß die oberen Zeilen nicht funktionierten. Und deshalb hab ich sie irgendwann entfernt.

Das hier funktioniert NICHT:

Delphi-Quellcode:
procedure TPreview.FormCreate(Sender: TObject);
var
  OldStyle: Integer;
  hWnd: THandle;
  Rec: TRect;
begin
  hWnd := StrToIntDef(ParamStr(2), 0);
  GetWindowRect(hWnd, Rec);
  SetBounds(0, 0, Rec.Right - Rec.Left, Rec.Bottom - Rec.Top);

  OldStyle := GetWindowLong(Handle, GWL_STYLE);
  SetWindowLong(Handle, GWL_STYLE, (OldStyle and not WS_POPUP) or WS_CHILD or WS_VISIBLE);

  BorderStyle := bsNone; // <<<<<<<<<< NACH

  Windows.SetParent(Self.Handle, hWnd);
end;
Das hier funktioniert korrekt:

Delphi-Quellcode:
procedure TPreview.FormCreate(Sender: TObject);
var
  OldStyle: Integer;
  hWnd: THandle;
  Rec: TRect;
begin
  hWnd := StrToIntDef(ParamStr(2), 0);
  GetWindowRect(hWnd, Rec);
  SetBounds(0, 0, Rec.Right - Rec.Left, Rec.Bottom - Rec.Top);

  BorderStyle := bsNone; // <<<<<<<<<< VOR

  OldStyle := GetWindowLong(Handle, GWL_STYLE);
  SetWindowLong(Handle, GWL_STYLE, (OldStyle and not WS_POPUP) or WS_CHILD or WS_VISIBLE);

  Windows.SetParent(Self.Handle, hWnd);
end;
Da mein letzter Bildschirmschoner schon länger her ist und ich das Preview Fenster jedes mal neu schreibe und dieses mal BorderStyle hinter SetWindowLong gesetzt habe und deshalb SetWindowLong keine Wirkung hatte und ich auf der Suche nach dem Fehler nach und nach alles entfernte und ganz einfach vergessen habe, daß beim Style einige Flags gesetzt werden müssen, habe ich letztendlich auch SetWindowLong entfernt.

Ich könnte mich jetzt versuchen rauszureden, ich hab es einfach vergessen. Vielleicht sollte ich mir mal ein Tutorial schrieben. Ich hatte mich mal wirklich ausführlich damit beschäftigt und jetzt passiert mir sowas. Man vergisst genauso schnell wie man es lernt.

Popov 18. Nov 2007 10:35

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Zitat:

Zitat von hathor
Betrifft Directive - So geht's:

Delphi-Quellcode:
program NurTest;
...
{$R *.RES}
{$D SCRNSAVE : Test Screen Saver}
...
Offensichtlich darf bei meinem DELPHI 2007 diese Directive erst NACH der $R-Directive
auftauchen. Im Übrigen sieht man sie nur mit geeigneten Programmen, z.B. Hexeditor.
Siehe Anhänge.

Letztendlich ist es unwichtig. Früher hatte diese Direktive beim Bildschirmschoner eine Bedeutung. Auch wenn sie heute noch in so ziemlich jedem BS Tutorial steht, was zeigt, daß einige die Tutorials schreiben einfach nicht wissen was sie da schreiben, sondern einfach zum Teil nur abschreiben, so hat diese Direktive nicht die Funktion die sei früher hatte. Früher, in den 8.3 Zeiten, konnte man so dem Bildschirmschoner einen langen Namen geben. Seit Windows 9x hat diese Direktive keinen Einfluß auf den Namen. Zumindest nicht bei Delphi zwischen D3 und D7 und Windows 98 und XP. Ich hab alle Varianten getestet, keine Wirkung. Wenn ich also diese Zeile noch drin hatte, dann eher aus sentimentalen Gründen.

Allerdings gibt es tatsächlich eine Möglichkeit einen BS Namen unabhängig dem Datei Namen zu setzten. Nur ist mir der nicht bekannt. Auch wenn ich schon seit Jahren dran suche.

Luckie 18. Nov 2007 16:12

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Warum hat der Threadtitel eigentlcih nichts mit dem Problem bzw. der Frage zu tun? :roll: Ich dachte eigentlich, dass du la´nge genug dabei bist, dass du wüsstest, wie man seinen Thread benennt.

Popov 18. Nov 2007 17:05

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Zitat:

Zitat von Luckie
Warum hat der Threadtitel eigentlcih nichts mit dem Problem bzw. der Frage zu tun? :roll: Ich dachte eigentlich, dass du la´nge genug dabei bist, dass du wüsstest, wie man seinen Thread benennt.

Wenn du dir den Text im ersten Beitrag durchliest, dann wirst du erkennen, daß das Problem gar nicht klar war. Erst im Laufe des Threads hat sich nach und nach rausgestellt, daß es die Bildschirmschoner Preview war, bis zuletzt das Problem erkannt wurde.

Warum dann aber nicht gleich geschrieben, daß es ein Bildschirmschoner Problem ist? Zum Zeitpunkt der Threaderstelleung stelle sich mir die Frage ob es überhaupt ein Bildschirmschoner Problem ist, denn die Eigenschaften von Anzeige produzierten immer frische Prozesse, auch bei einem leeren Konfigurationsfenster. Und das konnte nicht sein. Erst später stellte ich fest, daß der Konfigurationsfenster im gleichen Moment geschlossen wurde wie ein neuer Preview Prozess erstellt wurde. Nur erkannte ich es damals noch nicht. Für mich sah es so aus als ob das Konfigurationsfenster das mit Close beendet wurde, wobei dieses Fenster in dem Moment das Mainfenster war, nicht geschlossen werden konnte.

Für mich war also zu dem Zeitpunkt dieses Problem ein Problem was nicht nicht sein konnte. Es konnte nicht sein, daß sowohl Preview, wie Konfiguration und Vorschau Prozesse erstellten, denn alle waren unterschiedlich programmiert. Er war zu dem Zeitpunkt also ein unerklärliches Etwas was ich eigentlich nicht beschreiben konnte.

Bornemaxx 28. Nov 2007 18:19

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Zitat:

Zitat von Popov
...
Allerdings gibt es tatsächlich eine Möglichkeit einen BS Namen unabhängig dem Datei Namen zu setzten. Nur ist mir der nicht bekannt. Auch wenn ich schon seit Jahren dran suche.

.. genau danach habe ich heute gesucht, als ich auf diesen Thread gestoßen bin. Da hier leider nichts zu finden war, habe ich mir mal die Original-BS genauer angesehen. Und die Lösung gefunden ! :bounce2:
In der String-Table gibt es einen Eintrag mit der Nummer 1, der enthält den String, der als Name angezeigt wird.
Erzeugen kann man den mittels einer rc/res-Datei, die man mit einbindet. In der rc-Datei muß stehen:
Code:
STRINGTABLE
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
{
1,    "Mein Bildschirmschoner"
}
Habe es getestet unter XP und 98, da funktioniert es. unter NT und 95 scheint es nicht zu klappen, auch nicht mit der $D Direktive.
Viel Spaß beim Testen.

Viele Grüße

Mirko
(ganz neu hier, siehe Beitragszahl.)

hathor 28. Nov 2007 19:59

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Zitat:

Zitat von Bornemaxx
...(ganz neu hier, siehe Beitragszahl.)

Oje, das fängt ja gut an!

Ich bekomme eine Fehlermeldung - bist Du sicher, dass das was mit Delphi (oder mit Reactos???) zu tun hat?

[DCC Fehler] E2161 RLINK32: Unsupported 16bit resource in file "F:\Borland Studio Projects\31-LeererBildschirmschoner\test.res"

Bornemaxx 28. Nov 2007 20:15

Re: Probleme mit Bildschirmschonervorschau
 
Hallo hathor,
Ich hoffe, Deine Antwort bezieht sich auf meinen Tip zur Anzeige des Bildschirmschoner-Namens.

Also von Anfang an: Ich nutze Delphi 5.
Habe eine Datei namens string1.rc erstellt, diese enthält die o.g. Zeilen. Diese dann in der Eingabeaufforderung übersetzt mittels "brcc32 -r string1.rc" (brcc32 steht im Delphi-Verzeichnis unter \bin, sollte aber durch die Pfadangaben überall gefunden werden). Dadurch erhalte ich eine Datei namens string.res und die binde ich ein per {$R string1.res}. Damit funktioniert es bei mir jedenfalls.
Ich drück Dir die Daumen.

Gruß Mirko

Popov 28. Nov 2007 20:16

Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Zitat:

Zitat von Bornemaxx
Code:
STRINGTABLE
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
{
1,    "Mein Bildschirmschoner"
}
Habe es getestet unter XP und 98, da funktioniert es. unter NT und 95 scheint es nicht zu klappen, auch nicht mit der $D Direktive.
Viel Spaß beim Testen.

Getestet habe ich dein Tipp noch nicht, aber so weit war ich eigentlich auch schon. Ich werde deinen Tipp nochmal testen, aber das mit der Ressource habe ich auch schon in 20 verschiedenen Varianten ausprobiert. Neu ist das für mich also nicht. Aber ich werde es trotzdem testen.

Popov 28. Nov 2007 20:28

Re: Probleme mit Bildschirmschonervorschau
 
Ich hab es ausprobiert, funktionieren tut es aber nicht. Ich hab es mit Delphi 3 und Delphi 7 ausprobiert.

Erstellt habe ich die Datei STRING.RC

Delphi-Quellcode:
STRINGTABLE
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
{
1,   "Mein Bildschirmschoner"
}
dann die Datei RESBUILD.BAT

Delphi-Quellcode:
@brcc32 STRING.RC
Ergebnis war die STRING.RES

Diese hab ich in der Projektdatei eingebunden

Delphi-Quellcode:
{$R STRING.RES}
Hat nichts gebracht.

Aber trotzdem danke.

Bornemaxx 28. Nov 2007 20:45

Re: Probleme mit Bildschirmschonervorschau
 
Liste der Anhänge anzeigen (Anzahl: 1)
@ Popov
Schade, ich gehe davon aus, dass die *.res auch im Projektverzeichnis liegt. Aber mit einem Resourcen-Editor kann man sich das anzeigen lassen. Im Anhang ein Bild wie es bei mir aussieht.

Gruß Mirko

Popov 29. Nov 2007 18:10

Re: Probleme mit Bildschirmschonervorschau
 
Zitat:

Zitat von Bornemaxx
@ Popov
Schade, ich gehe davon aus, dass die *.res ...

An der RES liegt es nicht. Die ist korrekt kompiliert und auch eingebunden.

Bornemaxx 29. Nov 2007 20:27

Re: Probleme mit Bildschirmschonervorschau
 
Liste der Anhänge anzeigen (Anzahl: 1)
Habe gerade noch mal schnell ein Test-Projekt erstellt. ( Ich weiß,es ist unsauber, aber für den Test reicht es.) Liegt komplett im Anhang. Habe es als *.exe compiliert und nach *.scr umbenannt und nach Windows\system32 kopiert. Dann Desktop->Eigenschaften->Bildschirmschoner. Dort wird in der Auswahlliste "Test-Bildschirmschoner" angezeigt. Es funktioniert auch, wenn man ohne die Datei "string1.res" compiliert und mit dem Resource-Hacker (z.B. hier: Resource-Hacker) die "string.res" importiert. Mit diesem Ding kann man auch den String Nummer 1 verändern und beim Beenden wieder compilieren. Das geht auch mit der bs_test.scr im Verzeichnis windows\system32.
Vielleicht kann ja auch mal jemand anderes die bs_test.scr testen, wäre interessant. Wie gesagt, ich nutze D5 und XP SP1.

Gruß Mirko

Bornemaxx 3. Dez 2007 20:53

Re: Probleme mit Bildschirmschonervorschau
 
Jetzt wird es komisch: Habe gerade die SCR-Datei einem Bekannten geschickt. Bei ihm wird auch nur der Dateiname angezeigt !!! Der Unterschied zu meinem System: Er benutzt XP Home und ich XP Professional !!!
Vielleicht findet sich ja noch jemand zum Testen.

Gruß Mirko

Delphi-Laie 25. Mai 2012 15:07

AW: Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Zitat:

Zitat von SirThornberry (Beitrag 703885)
meine Vermutung wäre das dein Programm in einer Schleife festhängt. Also das du ständig das Bild aktuallisierst und mit Application.Processmessages dafür sorgst das nachrichten verarbeitet werden. Dadurch das es in einer schleife geschieht kann das Programm jedoch nicht entladen werden. Das wäre meine Vermutung.

Diese Diskussion ist zwar schon einige Jahre alt, aber vor genau dem gleichen Problem stehe ich nun auch und finde keine Lösung.

Wenn man während der laufenden Bildschirmschonervorschauf auf "Testen" oder "Einstellungen" klickt, so müßte das Bildschirmschonerprogramm beendet und mit anderem Paremeter erneut gestartet werden.

Die Ereignisse "OnCloseQuery" und "OnClose" werden (in dieser Reihenfolge) aufgerufen, wenn man die BSS-Vorschau beenden möchte, also wird wohl der Beendenbefehl an das Programm gesendet. Das Beenden der (im Vorschaumodus eben nicht mit Tastendruck oder Mausklick beendbaren) Bildschirmschonervorschau mutiert damit aber leider im besten Falle zur Geduldsprobe oder ist sogar völlig unmöglich.

Der Timer wird zum Start nur einmal aufgerufen, und die Schonerschleife soll eigentlich für die Vorschaud und das eigentliche Schonen gleichermaßen allgemeingültig sein. Hier der Quelltext:

Delphi-Quellcode:
procedure TSaverForm.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled:=false;
if copy(upperCase(paramstr(1)),1,2)<>'/C' then
  begin
    while not abbruch do
    begin
    Application.ProcessMessages;
 
    //eigentlicher Quellcode des BSS bzw. dessen Vorschau
 
    end
  end;
Application.Terminate //alternativ: SaverForm.Close
end;

procedure TSaverForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
abbruch:=true
end;
Akustische Ausgaben verrieten mir zudem, daß OnCloseQuery und OnClose viele Male abwechselnd aufgerufen werden - vermutlich wegen des Application.ProcessMessages.

Wie kann man eine solche Schleife schnell und sicher beenden? Ich probierte schon alles mögliche, unter anderem, daß Programm direkt in der Schleife zu beenden, OnClose statt OnCloseQuerey zu benutzen, beides gemeinsam, nichts hilft. Mit einem regelmäßigen Timer hingegen ist das Programm quälend langsam.

Im eigentlichen Schonermodus reagiert es hingegen sofort auf Eingaben und beendet sich sogleich.

Delphi-Laie 25. Mai 2012 18:39

AW: Re: Eine Frage die nur die Glaskugel beantworten werden kann
 
Des Rätsels Lösung findet sich hier.

Das dortige Projekt auf das wesentliche, das hier das Problem zu lösen demonstrieren soll, reduziert, sieht die Projektdatei so aus:
Delphi-Quellcode:
program Bildschirmschoner;

uses
  Forms,
  SysUtils,
  Windows,
  Graphics,
  Classes,
  scrn in 'scrn.pas' {screen};

{$E SCR}
{$R *.RES}

var DemoWnd:hwnd;
MyRect:TRect;
ScrWidth,ScrHeight:Integer;
MyCanvas:TCanvas;

begin
  Application.Initialize;

  if Copy(UpperCase(ParamStr(1)),1,2)='/P' then
    begin
    DemoWnd := StrToInt(UpperCase(ParamStr(2)));
    while not IsWindowVisible(DemoWnd) do Application.ProcessMessages;
    GetWindowRect(DemoWnd,MyRect);
    ScrWidth:=succ(MyRect.Right-MyRect.Left);
    ScrHeight:=succ(MyRect.Bottom-MyRect.Top);
    MyRect:=Rect(0,0,ScrWidth-1,ScrHeight-1);
    MyCanvas := TCanvas.Create;
    MyCanvas.Handle := GetDC(DemoWnd);

    while IsWindowVisible(DemoWnd) do
      begin
      MyCanvas.Pixels[random(ScrWidth),random(ScrHeight)]:=random(10000000);
      //Application.ProcessMessages
      end;
    MyCanvas.Free;
    Halt
    end;

  Application.CreateForm(Tscreen, screen);
  Application.Run;
end.
In der Hauptschleife werden zur Demonstration einfach farbige Pixel im Vorschaufenster ausgegeben (Farbrauschen). Das süffisante an dieser Lösung ist, daß diese Schleife sogar ohne Application.ProcessMessages auskommt und dennoch sofort beendet wird, wenn die Vorschau eines anderen Bildschirmschoners gewählt wird.

Für alle, die es interessiert...

Popov 25. Mai 2012 18:54

AW: Probleme mit Bildschirmschonervorschau
 
Das "Problem" ist, dass eigenes Überwachen der Tasten oder Maus eigentlich falsch ist. Denn aktuelle Windows Versionen verschicken eine Message die einem sagt, dass man bitte den Bildschirmschoner beenden soll. Man kann die Message ignorieren und selbst Tasten überwachen, ist aber kein Stand der Technik.

Delphi-Laie 25. Mai 2012 19:09

AW: Probleme mit Bildschirmschonervorschau
 
Ja, ich hatte gehofft, daß der Meister der Schoner sich zu Wort meldet, danke!

Ist es demnach nicht optimal, auf OnKeyDown/OnKeyPress und/oder OnMouseMove des bildschirmfüllenden und -schonenden Hauptformulares zu reagieren und in den entsprechenden Ereignisbehandlungsprozeduren das Beenden des Programmes entweder auszulösen oder wenigstens vorzubereiten?

himitsu 25. Mai 2012 19:23

AW: Probleme mit Bildschirmschonervorschau
 
Die Schleife im Timer war schon unschön, aber nun auch noch Halt?

Wie währe es mit OnIdle?

Delphi-Quellcode:
begin
  if AnsiStartsText('/P',ParamStr(1)) then //if Copy(UpperCase(ParamStr(1)),1,2)='/P' then
    begin
      DemoWnd := StrToInt(ParamStr(2));
      while IsWindow(DemoWnd) and not IsWindowVisible(DemoWnd) do // war 'ne Endlosschleife, falls es das Fenster nicht mehr gibt, oder es nie sichtbar wird
        Sleep(50);
      GetWindowRect(DemoWnd,MyRect);
      ScrWidth:=succ(MyRect.Right-MyRect.Left);
      ScrHeight:=succ(MyRect.Bottom-MyRect.Top);
      MyRect:=Rect(0,0,ScrWidth-1,ScrHeight-1);
      MyCanvas := TCanvas.Create;
      try
        MyCanvas.Handle := GetDC(DemoWnd);
        while IsWindowVisible(DemoWnd) do
          MyCanvas.Pixels[random(ScrWidth),random(ScrHeight)]:=random($FFFFFF+1);
      finally
        MyCanvas.Free;
      end;
    end
  else
    begin
      Application.Initialize;
      Application.CreateForm(TScreen, Screen);
      Application.Run;
    end;
end.

Delphi-Laie 26. Mai 2012 08:34

AW: Probleme mit Bildschirmschonervorschau
 
Zitat:

Zitat von himitsu (Beitrag 1168137)
Die Schleife im Timer war schon unschön, aber nun auch noch Halt?

Der Timer war doch nur ein 1-Schuß-Starttimer, um OnCreate zu verlassen. Halt kann man tatsächlich mit Deiner Lösung vermeiden (werde ich auch so tun, weil ich noch ein IniFile-Objekt instanziieren und entladen muß).

Mit Deinem
Delphi-Quellcode:
while IsWindow(DemoWnd) and not IsWindowVisible(DemoWnd) do // war 'ne Endlosschleife, falls es das Fenster nicht mehr gibt, oder es nie sichtbar wird
  Sleep(50);
setzt die Vorschau allerdings erst mit einer Verzögerung von etlichen Sekunden ein, auch dann, wenn man/ich das Sleep auf 0 herabsetzt/herabsetze. Das Fenster muß doch - eigentlich - auch immer sichtbar sein, denn mit /P wird doch nur gestartet, wenn man im Fenster "Eigenschaften von Anzeige" aktiv herummacht. Wenn man natürlich selber im Textfenster auf der Kommandozeile den BS-Schoner mit /P startet, also mit aller Gewalt einen Zustand erzeugt, der nicht vorgesehen ist, dann ist es wohl möglich.

Ergänzung: Es mußte wohl die Nachrichtenschleife geleert werden. Mit
Delphi-Quellcode:
while IsWindow(DemoWnd) and not IsWindowVisible(DemoWnd) do Application.ProcessMessages
startet die Vorschau augenblicklich.

Das Problem, aus einer Schleife (und bitte kein 1-ms-Timer) mit oder ohne Application.ProcessMessages ohne spürbaren Zeitverzug herauszukommen, hat sich für mich ohnehin seit gestern erledigt.

Popov 26. Mai 2012 10:34

AW: Probleme mit Bildschirmschonervorschau
 
@Delphi-Laie

Natürlich kannst du auch auf Tasten oder Maus reagieren, wird wohl genauso funktionieren, ich sag ja nur, dass Windows (ich weiß aber nicht seit wann) auch eine Message verschickt wenn der ScreenSaver läuft und eine Taste gedrückt oder Maus bewegt wurde. In dem Fall entscheidet Windows ob der ScreenSaver beendet werden soll. Allerdings ist die Auswertung nicht weniger kompliziert als wenn man es einfach selbst macht, denn laut der Beschreibung soll man bei a so reagieren, bei b so, bei c so usw.

Was den Code angeht den du nutzt, soll das ein NonVCL ScrennSaver sein?

Delphi-Laie 26. Mai 2012 11:15

AW: Probleme mit Bildschirmschonervorschau
 
Gut, dann werde ich wohl diese komplizierte Methode vermeiden und einfach die Ereignisbehandlungsprozeduren verwenden.

Zitat:

Zitat von Popov (Beitrag 1168196)
Was den Code angeht den du nutzt, soll das ein NonVCL ScrennSaver sein?

Teils, teils. Ursprünglich nur VCL mit nur einem Formular für Vorschau und für den eigentlichen Schoner. Dazu muß dieses Formular entweder maximiert und bsNone laufen oder eben in das Vorschaufenster gepreßt werden. Und letzteres war eben nur schwierig und mit Verzögerungen abzubrechen. Die dargestellte Non-VCL-Lösung behebt diese Schwierigkeit, für den eigentlichen Schoner bleibt es beim Formular.

Ursprünglich wollte ich sogar für alle 3 Modi (Vorschau, Schoner und Konfiguration) nur ein Formular benutzen, aber damit tut man sich auch keine Freude an.

Popov 26. Mai 2012 11:43

AW: Probleme mit Bildschirmschonervorschau
 
Mit einem Fenster für alle Modi ist auch nicht so wild, man muß es nur richtig vorbereiten und auf paar Punkte achten.

Als erstens ist die Abfrage Art wie
Delphi-Quellcode:
if AnsiStartsText('/P',ParamStr(1)) then
Quatsch, sie ist nicht falsch, aber nicht effektiv. Effektiver ist die Parameter zuerst separat auszuwerten, wie z. B.

Delphi-Quellcode:
const
  ssmConfigure  = 1;       { Dialog 'Einstellungen' }
  ssmFullScreen = 2;       { Vollbildmodus }
  ssmPreview    = 3;       { Vorschau }
  ssmPassword   = 4;       { Dialog 'Passwort setzen' }
  ssmInstall    = 5;       { Installieren }

var
  ssMode: Byte;

...

    case Param1[1] of
    'C':     Result := ssmConfigure;   { Dialog 'Einstellungen' }
    'S':     Result := ssmFullScreen;  { Vollbildmodus }
    'P':     Result := ssmPreview;     { Vorschau }
...
Danach arbeitest du nur noch mit der globalen variable ssMode. In einem ein Fenster ScreenSaver reagierst du dann auf
Delphi-Quellcode:
if ssMode = ssmFullScreen
oder
Delphi-Quellcode:
if ssMode = ssmPreview
usw. Je nach ssMode reagierst du unterschiedlich. Ist es ssmFullScreen, arbeitet es wie ein ScreenSaver, ist es ssmPreview, abereitet es wie ein Programm, d. h. Tastendruck beendet das Programm nicht usw.

Dann solltest du soweit es geht alles was geht in zwei Funktionen packen für ScreenSaver begin und end, d. h. bestimmte Screensaver Funktionen sollten nicht unkontrolliert in einer normalen Prozedur behandelt werden, sondern in separaten eigenen Funktionen. Damit kannst du je nach ssMode sie aufrufen oder nicht.

Delphi-Laie 26. Mai 2012 12:05

AW: Probleme mit Bildschirmschonervorschau
 
Das ist mir durchaus klar, danke!

Also, der Bildschirmschoner wird für jeden Modus in diesem Modus neu gestartet.

Für den Vollschirmmodus, den eigentlichen Schonermodus, setzte ich den Mauscursor auf -1 (abgeschaltet) - und nach meiner Meinung auch nur in diesem (Bedingungen und Verzweigungen).

Erstaunlicherweise war der Mauscursor auch im Konfigurationsformular verschwunden. Ich setzte ihn daraufhin für diesen Modus sogar explizt auf crDefault (ist ja eigentlich schon die Starteinstellung), aber es änderte sich nichts, er wollte einfach nicht. Das war mir dann zuviel, ich hatte einfach kein Interesse, mich in diese Unwichtigkeit zu verbeißen. Also, wie schon gesagt, ich tat mir damit keine Freude. Auch muß man dann soviel an dem einen Formular "rummachen" und damit Quelltext erzeugen, daß zwei getrennte Formulare mit den entsprechenden, im Objektinspektor eingetragenen Startwerten auch ihre Berechtigung haben.

jaenicke 26. Mai 2012 14:02

AW: Probleme mit Bildschirmschonervorschau
 
Hier gibt es übrigens auch noch ein Beispiel, das habe ich mir nicht näher angeschaut, aber könnte ja interessant sein:
http://edn.embarcadero.com/article/26652

Ich selbst habe die Funktionalität in einer Klsse gekapselt, und zeichne dann nur auf das jeweilige Ziel (Vorschau oder echt). Das macht das ganze deutlich einfacher.

Delphi-Laie 26. Mai 2012 16:54

AW: Probleme mit Bildschirmschonervorschau
 
Die Vorschauschleife ist dort genauso gelöst wie weiter oben von mir hier veröffentlicht, danke!

Die eigentliche Zeichenfunktion lagerte ich in eine Prozedur aus:

Delphi-Quellcode:
procedure Ausgabe(canvas:TCanvas;x,y:word);
begin
//Quellcode für den Bildschirmschoner
end;
die so

Delphi-Quellcode:
while IsWindowVisible(DemoWnd) do Ausgabe(MyCanvas,scrWidth,scrHeight);


aufgerufen wird, das klappt soweit auch. x und y sind dabei natürlich die Abmessungen des Canvas, somit weiß die Prozedur, in welche Fläche (Ausdehnung derselben) sie zu zeichnen hat.

Nun wollte ich diesselbe Prozedur ja nicht nur für die Schonervorschau, sondern auch für das eigentliche Bildschirmschonen benutzen, deshalb ja die Prozedur. Doch der Aufruf vom als SaverScreen titulierten Formular

Delphi-Quellcode:
Ausgabe(SaverScreen.Canvas,SaverScreen.Width,SaverScreen.Height)


klappt natürlich nicht (wäre ja auch zu schön gewesen), es findet keine Ausgabe statt. Die Prozdur wird natürlich aufgerufen, das war das erste, was ich prüfte. Irgendetwas stimmt mit der Übergabe nicht. Ich probierte es schon mit Pointer, mit der Kreierung eines eigenen Canvas, dem ich das Handle des ScaverScreens respektive seines Canvas' zuwies, doch es tut sich einfach nichts, bis auf einmal, als wenigstens die Meldung kam, daß die Fläche kein Zeichnen erlaubt.

Wie bekommt man dieser Prozedur mitgeteilt, daß sie diesmal auf das Canvas des Schonerformulares zeichnen soll?

Edit: Die Übergabe des Canvas' klappt doch, der Fehler liegt woanders...

Edit 2: Fehler gefunden.

jaenicke 26. Mai 2012 18:58

AW: Probleme mit Bildschirmschonervorschau
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe mal ein kleines Beispiel gemacht wie ich mir das so vorstelle, siehe Anhang. ;-)
(Kompilierbar im Moment ausschließlich mit XE2.)


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:48 Uhr.

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