迈克Lischke的 TThemeServices 子类 Application.Handle, ,因此,它可以接收到广播通知从窗户(即 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;

该子类窗口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.

而这一切运作良好的-只要TThemeServices是唯一一个曾经的子类的应用程序的处理。

我有一个类似的单独的图书馆,这也要挂钩 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);

单是类似时,删除该单元最终确定:

initialization
   ...
finalization
    InternalDwmServices.Free;
end.

现在我们来到这个问题。我不能保证顺序,有人可能会选择访问 ThemeServicesDWM, ,每个申请他们的子类。我也不能知道了在德尔斐个附属机构将争取处理完毕的单位。

该子类都被去除的顺序错误,并有崩溃的应用程序关闭。

如何解决?我怎么可以 确保我把我的子类方法周围足够长的时间,直到的 其他的 那家伙是做了 之后我做了什么?(我不想泄漏存储器,毕竟)

也参看


更新: 我看到德尔斐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;

图片视频

换句话说:尝试类TApplication是一个错误,即Borland固定时,他们通过了迈克的 TThemeManager.

那很好可以意味着那里是没有办法消除子上 TApplication 在相反的顺序。有人把这种形式的回答,我会接受它。

有帮助吗?

解决方案

改变你的代码来电话 SetWindowSubclass, ,作为第你链接的建议。但是这只适用,如果每个人都使用相同的API,以修补的主题管理使用的相同的技术。API介绍了在Windows XP、因此没有危险,这是不适用的系统,这将是需要的。

应该没有问题,修补与主题管理。它的设计,以支持Windows XP,Microsoft不会支持了,并支持德尔福4至6,其Borland不支持了由于发展已经停止的所有相关的产品,它是安全的你叉的主题管理的项目没有下降的风险后由于将来的更新。

你不会真的引入的依赖。相反,你定一个错误,只有在这两个窗口观图书馆在使用相同的时间。用户的图书馆不需要有主题经理,你的工作,但是,如果他们想要使用两者,他们需要使用主题管理与你的修补程序应用。应该有很少的反对,因为他们已经有基本版本,所以它不喜欢他们会安装一个全新的图书馆。他们只是施加一个补丁和重新编译.

其他提示

而不是继承的TApplication窗口,或许可以使用AllocateHWnd()而不是要接受相同的广播节目的分开,因为它是一个顶级的窗口。

我想我会做到以下几点:

  • 把一个参考ThemeServices在初始部分的ThemeSrv.考绩制度。
  • 把一个参考DwmServices在初始部分的DwmSrv.考绩制度(我的猜测的名称单元)。

由于单元的定稿,在反的顺从的次序初始化,你的问题将得到解决。

你为什么不使用ApplicationEvents并用它来完成。没有必要插科打诨子类化。其他的方式是创造只有一个子类,并创建多通知的活动和订阅你的愿望。

欢呼

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top