加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Delphi:如何以相反的顺序删除子类?

发布时间:2020-12-15 09:27:17 所属栏目:大数据 来源:网络整理
导读:Mike Lischke的TThemeServices子类是Application.Handle,因此它可以在主题发生变化时从 Windows接收广播通知(即WM_THEMECHANGED). 它是Application对象窗口的子类: FWindowHandle := Application.Handle;if FWindowHandle 0 thenbegin // If a window handl
Mike Lischke的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;

然后,子类化的窗口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,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的句柄的人.

我有一个类似的单独的库,也想挂钩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,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,LParam);

当单位最终确定时,我的单身人士同样被删除:

initialization
   ...
finalization
    InternalDwmServices.Free;
end.

现在我们来解决问题.我不能保证某人可能选择访问ThemeServices或DWM的顺序,每个都应用他们的子类.我也不知道德尔福最终确定单位的顺序.

正在以错误的顺序删除子类,并且应用程序关闭时发生崩溃.

怎么修?我怎么能在ensure that i keep my subclassing method around long enough until the other guy is done之后完成? (毕竟我不想泄漏记忆)

也可以看看

> Raymond Chen: Safer Subclassing
> MSDN: Using Window Procedures
> Raymond Chen: When the normal window destruction messages are thrown for a loop

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

GRRRR

换句话说:尝试子类化TApplication是一个错误,Borland在他们采用Mike的TThemeManager时修复了这个错误.

这很可能意味着无法以相反的顺序删除TApplication上的子类.有人把它以答案的形式出现,我会接受它.

解决方法

更改您的代码以调用 SetWindowSubclass,就像您链接到建议的文章一样.但这只适用于每个人使用相同的API,因此修补主题管理器使用相同的技术.该API是在Windows XP中引入的,因此不存在它在需要它的系统上不可用的危险.

修补主题管理器应该没有问题.它旨在支持微软不再支持的Windows XP,并支持Delphi 4到6,Borland不再支持它.由于所有相关产品的开发已停止,因此您可以安全地分配主题管理器项目,而不会因未来的更新而落后.

你并没有真正引入依赖.相反,您正在修复仅在两个窗口外观库同时使用时才出现的错误.您的库的用户不需要使用Theme Manager来工作,但如果他们希望同时使用这两者,他们需要使用Theme Manager并应用您的补丁.应该没有什么异议,因为他们已经有基本版本,所以它不像他们要安装一个全新的库.他们只是应用补丁并重新编译.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读