Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.062 Beiträge
 
Delphi 12 Athens
 
#4

AW: Wann wird fremde TForm ausgeblendet

  Alt 14. Jun 2024, 12:17
Jupp, eine fremde Form im Programm.

Es ist ja nicht "meine" Form, und somit weiß ich nicht, ob nicht jetzt/irgendwann schon was am OnHide hängt. (Ja, eine Kopie des Wertes und dann das Aufrufen ... Problem ist dann, wenn irgendwann noch wer Anderes auch sowas macht)

Ich will einfach nur mitbekommen, wann sie ausgelendet wird, also eigentlich das Programm "anfängt" sich zu beenden.
Aber das so früh wie möglich. (über die "normalen" Wege der OTA, sind zwischen dem Verschwinden der MainForm aus der Taskleiste und meinem Taskbareintrag 30-60 Sekunden, wo man nix sieht, bis es wirklich weg ist)

z.B. die Hauptform vom Delphi, in einem Designtimepackage.

Edit: "VCL oder non-VCL" bedeutet VCL oder FMX ? Oder sprechen wir hier doch nicht von einem Delphi-Programm?
VCL oder direkt per WinAPI
z.B. das WM_SHOWWINDOW+SW_PARENTCLOSING hatte ich mit einem TPanel probiert (hätte aber auch eine TForm sein können) oder eben per CreateWindowEx.





Das Projekt macht jetzt nicht viel,
  • also zu Beginn den SplashScreen in der Taskleiste
    (wenn Delphi im Hintergrund aufgeht und man noch was Anderes macht ... und wo Delphi vielleicht hängenbleibt, weil z.B. Probleme beim Laden des letzten Projektes, mit Warten in einem Dialog ... unbemerkt im Hintergrund versteckt)
  • sowie beim Beenden ebenfalls in der Taskleiste (hier ist allerdings aktuell öfters noch eine längere Lücke ... DevExpress und Anderes wird zwischenzeitlich entladen)
    bis die BDS.exe wirklich komplett weg ist

    Delphi bleibt manchmal leise hängen, oder eventuell auch nur mit 100% CPU minutenlang irgendwas machend,
    und dann knallt es im FinalBuilder, weil Designtimepackages sich nicht neu erstellen lassen, da Datei gesperrt.
Delphi-Quellcode:
unit Package1Unit;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Classes,
  System.Win.ComObj, Winapi.ShlObj, Winapi.Dwmapi,
  Vcl.ExtCtrls, Vcl.Forms;

//procedure Register;

implementation

type
  TStartDummy = class
  private
    class procedure AssignToStart;
    class procedure WaitTimer(Sender: TObject);
  end;

  TDestroyDummy = class(TPanel) // TPanel wegen WMShowWindow (eigentlich TComponent)
  public
    procedure BeforeDestruction; override;
  private
    procedure WMShowWindow(var Msg: TWMShowWindow); message WM_SHOWWINDOW;
  end;

class procedure TStartDummy.AssignToStart;
var
  Taskbar: ITaskbarList3;
begin
  for var i := Screen.CustomFormCount - 1 downto 0 do
    if (Screen.CustomForms[i].ClassType = TForm) and (Screen.CustomForms[i].Caption = 'SplashScreen') then
      begin
        // in Taskleiste anteigen
        ShowWindow(Screen.CustomForms[i].Handle, SW_HIDE);
        SetWindowLong(Screen.CustomForms[i].Handle, GWL_EXSTYLE, GetWindowLong(Screen.CustomForms[i].Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW or WS_EX_APPWINDOW);
        ShowWindow(Screen.CustomForms[i].Handle, SW_SHOW);

        // Texte und Arbeitsanzeige
        Screen.CustomForms[i].Caption := 'Delphi wird gestartet';
        Taskbar := CreateComObject(CLSID_TaskbarList) as ITaskbarList3;
        {CheckOSError}(Taskbar.SetProgressState(Screen.CustomForms[i].Handle, TBPF_INDETERMINATE));
        //{CheckOSError}(Taskbar.SetThumbnailTooltip(Screen.CustomForms[i].Handle, 'Delphi wird gestartet'));
      end;

  //TDestroyDummy.Create(Application.MainForm); // an Hauptfenster hängen
  with TDestroyDummy.Create(Application.MainForm) do begin // an Hauptfenster hängen
    Parent := Application.MainForm;
    BevelOuter := TPanelBevel.bvNone;
    Width := 1;
    Height := 1;
    TabStop := False;
    Visible := True;
  end;
end;

class procedure TStartDummy.WaitTimer(Sender: TObject);
var
  B: Boolean;
begin
  try
    B := Assigned(Application) and Assigned(Application.MainForm);
    for var i := Screen.CustomFormCount - 1 downto 0 do
      if (Screen.CustomForms[i].ClassType = TForm) and (Screen.CustomForms[i].Caption = 'SplashScreen') then
        B := True;

    if B then begin
      TStartDummy.AssignToStart;
      Sender.Free;
    end;
  except
  end;
end;

procedure TDestroyDummy.BeforeDestruction;
var
  WndClass: TWndClass;
  TaskWnd: HWND;
  Taskbar: ITaskbarList3;
  Param: BOOL;
begin
  try
    FillChar(WndClass, SizeOf(WndClass), 0);
    WndClass.lpfnWndProc := @DefWindowProc;
    WndClass.hInstance := HInstance;
    WndClass.hIcon := 0;
    WndClass.lpszClassName := 'TaskbarDestroyDummy';
    {Win32Check}(RegisterClassW(WndClass) {<> 0});

    TaskWnd := CreateWindowEx(WS_EX_TOOLWINDOW or WS_EX_APPWINDOW, WndClass.lpszClassName, PChar('Delphi wird beended'),
      WS_VISIBLE {or WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS}, 100, 100, 0, 0, 0, 0, HInstance, nil);
    {Win32Check(TaskWnd <> 0);}

    Taskbar := CreateComObject(CLSID_TaskbarList) as ITaskbarList3;
    {CheckOSError}(Taskbar.SetProgressState(TaskWnd, TBPF_INDETERMINATE));
    {CheckOSError}(Taskbar.SetThumbnailTooltip(TaskWnd, 'Delphi wird beendet'));

    Param := True;
    {CheckOSError}(DwmSetWindowAttribute(TaskWnd, DWMWA_FORCE_ICONIC_REPRESENTATION, @Param, SizeOf(BOOL)));
    {CheckOSError}(DwmSetWindowAttribute(TaskWnd, DWMWA_HAS_ICONIC_BITMAP, @Param, SizeOf(BOOL)));

    inherited;
  except
  end;
end;

procedure TDestroyDummy.WMShowWindow(var Msg: TWMShowWindow);
begin
  MessageBox(0, PChar(IntToStr(Msg.Status)), nil, 0);
end;

//procedure Register; // wenn in HKEY_CURRENT_USER\Software\Embarcadero\BDS\22.0\Known IDE Packages
//begin
// TStartDummy.AssignToStart;
//end;

initialization
  with TTimer.Create(nil) do begin // wenn in HKEY_CURRENT_USER\Software\Embarcadero\BDS\22.0\Known Packages
    OnTimer := TStartDummy.WaitTimer;
    Interval := 1;
    Enabled := True;
  end;

finalization
  try
    if Assigned(Application) and Assigned(Application.MainForm) then
      for var C in Application.MainForm do
        if C is TDestroyDummy then begin
          C.Free;
          Break;
        end;
  except
  end;

end.
37 KB als Release (2-3 MB als Debug)

"register" kommt erst eine Weile nach dem erscheinen des SplashScreen (Known IDE Packages früher oder Known Packages bissl bis viel später)
"initialization" im Known IDE Packages leider schon vor dem SplashScreen (drum der böse Timer)



Und dann das die Registrierung von "Known Packages" ins "Known IDE Packages" verschieben,
bzw. garnicht das Package "installieren" und direkt den Eintrag dort rein.
C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\Package1.bpl

Achtung, ist es im "Known IDE Packages" registriert, dann lässt sich das Projekt im Delphi nicht mehr kompilieren. (vorher also entfernen oder umbennen ... _ anhängen)

Der Code ist für Delphi 11.
Ab Delphi 12 ist es nochmal extrem einfacher, da dort die VCL alles bietet,
von Form.ShowInTaskBar über TTaskbar (Form.TaskbarHandler).

Delphi-Quellcode:
// Der SplashScreen ist eine manuell zusammengebaute TForm.
SplashScreen.Caption := 'Delphi startet';
SplashScreen.ShowInTaskBar := True;
TaskBar := TTaskBar.Create(SplashScreen); // SplashScreen.TaskbarHandler
TaskBar.ProgressState := TTaskBarProgressState.Indeterminate;
TaskBar.ToolTip := 'Delphi startet';

Echt mal, ich verstehe einfach nicht, warum sich Emba seit Jahrzehnten dagegen wehrt, beim Starten das Delphi in der Taskleiste anzuzeigen,
also SetWindowLong+WS_EX_APPWINDOW, bzw. aktuell TForm.ShowInTaskBar.
(wenigsten ist der nicht StayOnTop)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (14. Jun 2024 um 17:01 Uhr)
  Mit Zitat antworten Zitat