Frage

Mike Lischke des TThemeServices Subklassen Application.Handle, so dass es Broadcast-Meldungen aus dem Windows empfangen kann (das heißt WM_THEMECHANGED), wenn Änderungen Thematisierung.

Es Unterklassen des Fensters Application Objekt:

FWindowHandle := Application.Handle;
if FWindowHandle <> 0 then
begin
 // If a window handle is given then subclass the window to get notified about theme changes.
 {$ifdef COMPILER_6_UP}
    FObjectInstance := Classes.MakeObjectInstance(WindowProc);
 {$else}
    FObjectInstance := MakeObjectInstance(WindowProc);
 {$endif COMPILER_6_UP}
 FDefWindowProc := Pointer(GetWindowLong(FWindowHandle, GWL_WNDPROC));
 SetWindowLong(FWindowHandle, GWL_WNDPROC, Integer(FObjectInstance));
end;

Das subclassed Fenster procdure dann der Fall ist, wie es zu, WM_DESTROY Nachricht angenommen hat, entfernen Sie die Unterklasse, und dann die WM_DESTROY Nachricht weitergeben:

procedure TThemeServices.WindowProc(var Message: TMessage);
begin
  case Message.Msg of
     WM_THEMECHANGED:
        begin
               [...snip...]
        end;
     WM_DESTROY:
        begin
          // If we are connected to a window then we have to listen to its destruction.
          SetWindowLong(FWindowHandle, GWL_WNDPROC, Integer(FDefWindowProc));
          {$ifdef COMPILER_6_UP}
             Classes.FreeObjectInstance(FObjectInstance);
          {$else}
             FreeObjectInstance(FObjectInstance);
          {$endif COMPILER_6_UP}
          FObjectInstance := nil;
        end;
  end;

  with Message do
     Result := CallWindowProc(FDefWindowProc, FWindowHandle, Msg, WParam, LParam);
end;

Das TThemeServices Objekt ist ein Singleton, während Einheit Fertigstellung zerstört:

initialization
finalization
  InternalThemeServices.Free;
end.

Und das alles funktioniert gut -. Solange TThemeServices ist der einzige Mann, der jemals den Griff des Anwendungsunterklasse

ich habe eine ähnliche Singleton Bibliothek, die auch will Application.Handle einzuhaken, so kann ich Sendungen empfangen können:

procedure TDesktopWindowManager.WindowProc(var Message: TMessage);
begin
case Message.Msg of
WM_DWMCOLORIZATIONCOLORCHANGED: ...
WM_DWMCOMPOSITIONCHANGED: ...
WM_DWMNCRENDERINGCHANGED: ...
WM_DESTROY:
    begin
        // If we are connected to a window then we have to listen to its destruction.
        SetWindowLong(FWindowHandle, GWL_WNDPROC, Integer(FDefWindowProc));
        {$ifdef COMPILER_6_UP}
        Classes.FreeObjectInstance(FObjectInstance);
        {$else}
        FreeObjectInstance(FObjectInstance);
        {$endif COMPILER_6_UP}
        FObjectInstance := nil;
    end;
end;

with Message do
    Result := CallWindowProc(FDefWindowProc, FWindowHandle, Msg, WParam, LParam);

und mein Singleton in ähnlicher Weise entfernt wird, wenn das Gerät finalisiert:

initialization
   ...
finalization
    InternalDwmServices.Free;
end.

Nun kommen wir zu dem Problem. Ich kann keine Garantie für die Reihenfolge, in der jemand Zugang ThemeServices oder DWM wählen können, von denen jede ihre Unterklasse gelten. Ebenso wenig kann ich wissen, die Reihenfolge, in der Delphi-Einheiten abzuschließen.

Die Unterklassen werden in der falschen Reihenfolge entfernt, und es gibt einen Absturz auf Anwendung schließen.

Wie zu beheben? Wie kann ich sicher, dass ich meine Subklassifizieren Methode halten lange genug bis die andere Kerl nach mir getan wird wird getan? (Ich möchte nicht, Speicher verlieren, nachdem alle)

Siehe auch


Update: Ich sehe Delphi 7 löst der Fehler durch TApplication neu zu schreiben. > <

procedure TApplication.WndProc(var Message: TMessage);
...
begin
   ...
   with Message do
      case Msg of
      ...
      WM_THEMECHANGED:
          if ThemeServices.ThemesEnabled then
              ThemeServices.ApplyThemeChange;
      ...
   end;
   ...
end;

Grrrr

Mit anderen Worten: zu Unterklasse TApplication Versuch war ein Fehler, dass Borland festgelegt, wenn sie Mikes TThemeManager angenommen.

Das ist sehr gut bedeuten kann, dass es keine Möglichkeit gibt Subklassen auf TApplication in umgekehrter Reihenfolge zu entfernen. Jemand setzte sich in Form einer Antwort, und ich werde es akzeptieren.

War es hilfreich?

Lösung

Ändern Sie den Code, um die Anruf SetWindowSubclass , wie der Artikel, den Sie verknüpft berät. Aber das funktioniert nur, wenn jeder die gleiche API verwendet, so Patch Theme Manager auf die gleiche Technik zu verwenden. Die API in Windows XP eingeführt wurde, so dass es keine Gefahr, dass es auf den Systemen nicht verfügbar ist, wo es benötigt wird.

Es sollte kein Problem sein mit Theme Manager Patchen. Es wird entwickelt, Windows XP zu unterstützen, die Microsoft nicht mehr unterstützt, und Delphi 4 bis 6 zu unterstützen, die Borland nicht mehr unterstützt. Da die Entwicklung auf allen relevanten Produkten aufgehört hat, ist es sicher für Sie das Theme Manager Projekt ohne die Gefahr eines Absturzes hinter aufgrund zukünftigen Updates gabeln.

Sie sind die Einführung nicht wirklich eine Abhängigkeit. Vielmehr sind Sie einen Fehler behebt, die nur vorhanden ist, wenn beide Fenster Aussehen Bibliotheken im Einsatz zugleich sind. Benutzer Ihrer Bibliothek nicht für Ihr zur Arbeit haben Theme Manager brauchen, aber wenn sie beide verwenden möchten, müssen sie Theme Manager verwenden, um mit Ihren Patches angewendet. Es soll wenig dagegen einzuwenden, da sie bereits die Basisversion hat, so ist es nicht, wie sie eine völlig neue Bibliothek zu installieren würde. Sie haben nur einen Patch anwenden und neu zu kompilieren.

Andere Tipps

Anstatt Subklassen die TApplication Fenster, vielleicht können Sie verwenden AllocateHWnd () statt die gleichen Sendungen getrennt zu erhalten, da es sich um ein Fenster der obersten Ebene der eigenen ist.

ich glaube, ich würde wie folgt vor:

  • Legen Sie einen Verweis auf ThemeServices im Initialisierungsabschnitt von ThemeSrv.pas.
  • Legen Sie einen Verweis auf DwmServices im Initialisierungsabschnitt von DwmSrv.pas (Ich bin den Namen Ihrer Einheit erraten).

Da Einheiten in umgekehrter Reihenfolge von der Reihenfolge der Initialisierung abgeschlossen sind, wird Ihr Problem gelöst werden.

Warum gehst du nicht einfach die Application verwenden und mit ihr geschehen. Keine Notwendigkeit, Herumspielen mit Subklassen. Der andere Weg ist nur eine Unterklasse zu erstellen und Multi-notify Ereignisse erstellen und so viele abonnieren, wie Sie wollen.

Prost

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top