Mike Lischke 的TThemeServices
子类Application.Handle
,以便它可以WM_THEMECHANGED
在主题更改时接收来自 Windows(即)的广播通知。
它继承了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;
子类化的窗口过程然后按照它应该的那样发送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.
现在我们来解决这个问题。我不能保证某人可能选择访问ThemeServices
或的顺序DWM
,每个都应用他们的子类。我也不知道德尔福最终确定单位的顺序。
子类以错误的顺序被删除,并且应用程序关闭时发生崩溃。
怎么修?我如何确保我的子类化方法保持足够长的时间,直到其他人在我完成后完成?(毕竟我不想泄漏内存)
也可以看看
更新:我看到 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;
呸呸呸
换句话说:尝试继承 TApplication 是一个错误,Borland 在采用 Mike 的TThemeManager
.
这很可能意味着没有办法以TApplication
相反的顺序删除子类。有人以答案的形式提出,我会接受。