Вопрос

Майк Лищес TThemeServices подклассы Application.Handle, Так что он может получать уведомления о вещаниях из Windows (т.е. WM_THEMECHANGED) при тематике меняется.

Это подклассы Application Окно объекта:

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;

Subclassed Window Procdure, как это должно, WM_DESTROY сообщение, удалить его подкласс, а затем пройти WM_DESTROY сообщение о:

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;

То TThemeServices Объект - это синглтон, уничтоженный во время завершения единицы:

initialization
finalization
  InternalThemeServices.Free;
end.

И что все работает хорошо - до тех пор, пока цеменному сервису - единственный парень, который когда-либо подклассирует ручку приложения.

У меня есть подобная библиотека Singleton, которая также хочет зацепить Application.Handle Так что я могу получать трансляции:

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);

А также мой Singleton аналогично удален, когда устройство завершается:

initialization
   ...
finalization
    InternalDwmServices.Free;
end.

Теперь мы пришли к проблеме. Я не могу гарантировать заказ, в котором кто-то может выбрать доступ к доступу ThemeServices или DWM, Каждый из которых наносит свой подкласс. Я не могу знать порядок, в котором Delphi завершит единицы.

Подклассы удаляются в неправильном порядке, и есть сбой на приложении близко.

Как исправить? Как я могу убедитесь, что я держу свой метод подклассов достаточно долго, пока разное Парень сделан После того, как я закончил? (Я не хочу утерять память, ведь)

Смотрите также


Обновлять: Я вижу Delphi 7 решает ошибку, переписывая TApplication. ><

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

ГРРРР

Другими словами: попытка подкласса подсказка была ошибками, что Борланд фиксировал, когда они приняли Майк TThemeManager.

Что очень хорошо может означать, что нет способа удалить подклассы на TApplication в обратном порядке. Кто-то положил это в форме ответа, и я приму это.

Это было полезно?

Решение

Измените свой код, чтобы позвонить SetWindowSubclass, Как статья, которую вы связали, советует. Но это только работает, если все используют один и тот же API, поэтому Patch Theme Manager использовать ту же технику. API был введен в Windows XP, поэтому нет никакой опасности, что он не доступен в системах, где это потребуется.

Не должно быть проблем с исправлению тематического менеджера. Он предназначен для поддержки Windows XP, который Microsoft больше не поддерживает, и поддерживать Delphi с 4 по 6, который Borland не поддерживает больше. Поскольку разработка прекратилась по всем соответствующим продуктам, вам будет безопасно в виду проект The Cheme Manager без риска отставания из-за будущих обновлений.

Вы не очень представляете зависимость. Скорее, вы исправляете ошибку, присутствую только, когда оба библиотеки внешнего вида используются одновременно. Пользователям вашей библиотеки не нужно иметь тематическую менеджеру для вашего на работу, но если они хотят использовать оба, им нужно использовать тематический менеджер с применяемыми патчами. Должно быть мало возражения для этого, так как у них уже есть базовая версия, поэтому она не так, как они будут устанавливать совершенно новую библиотеку. Они просто будут применять патч и перекомпиляция.

Другие советы

Вместо того, чтобы подклассное окно Trapplication, возможно, вы можете использовать AllocateHwnd () вместо этого, чтобы получить те же трансляции отдельно, поскольку это окно самого верхнего уровня.

Я думаю, что я сделаю следующее:

  • Поместите ссылку на тематические сервисы в разделе инициализации Themesrv.pas.
  • Поместите ссылку на DWMServices в разделе инициализации DWMMSRV.PAS (я думаю, название вашего устройства).

Поскольку единицы завершены в обратном порядке с порядка инициализации, ваша проблема будет решена.

Почему бы вам не просто использовать apharesEvents и делать с ним. Не нужно возиться с субклассиями. Другой способ состоит в том, чтобы создать только один подкласс и создавать многоуровневые события и подписаться столько, сколько вы хотите.

Ваше здоровье

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top