i need to know when my application recieves a WM_SETTINGCHANGE
message (formerly known as WM_WININICHANGE
).
Problem is that the message pump in TApplication sends it down a black hole (default handler) before i can get a chance to see it:
procedure TApplication.WndProc(var Message: TMessage);
...
begin
Message.Result := 0;
for I := 0 to FWindowHooks.Count - 1 do
if TWindowHook(FWindowHooks[I]^)(Message) then Exit;
CheckIniChange(Message);
with Message do
case Msg of
WM_SETTINGCHANGE:
begin
Mouse.SettingChanged(wParam);
Default; <----------------------*poof* down the sink hole
end;
...
end;
...
end;
The procedure CheckIniChange()
doesn't throw any event i can handle, neither does Mouse.SettingChanged()
.
And once the code path reaches Default
, it is sent down the DefWindowProc
drain hole, never to be seen again (since the first thing the WndProc does is set the Message.Result
to zero.
i was hoping to assign a handler to a TApplicationEvents.OnMessage event:
procedure TdmGlobal.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
case Msg.message of
WM_SETTINGCHANGE:
begin
// Code
end;
end;
end;
But the OnMessage event is only thrown for messages that come through the message pump. Since the WM_SETTINGCHANGE
message is "handled", it never sees the
PeekMessage
TranslateMessage
DispatchMessage
system.
How can i respond to the windows broadcast WM_SETTINGCHANGE
?
Edit2: For older versions the usual message intercept should work...
[...]
private
procedure WMSettingChange(var Message: TWMSettingChange); message WM_SETTINGCHANGE;
[...]
procedure TForm1.WMSettingChange(var Message: TWMSettingChange);
begin
showMessage('SettingChange message intercept');
end;
Edit: Ooops! Did not see it was for D5. The following was in D2007+.
Use an OnSettingChange in your Application:
procedure TApplication.SettingChange(var Message: TWMSettingChange);
begin
if Assigned(FOnSettingChange) then
with Message do
FOnSettingChange(Self, Flag, Section, Result);
end;
You can test with this code. Try and change the height or docking side of the TaskBar...
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnSettingChange := MySettingChange;
end;
procedure TForm1.MySettingChange(Sender: TObject; Flag: Integer;
const Section: string; var Result: Integer);
begin
showMessage('setting changed');
end;
The answer was in my question, the dangerous, undocumented, use of HookMainWindow
:
procedure TdmGlobal.DataModuleCreate(Sender: TObject);
begin
...
Application.HookMainWindow(SettingChangeHook);
end;
procedure TdmGlobal.DataModuleDestroy(Sender: TObject);
begin
Application.UnhookMainWindow(SettingChangeHook);
end;
function TdmGlobal.SettingChangeHook(var Message: TMessage): Boolean;
begin
case Message.Msg of
WM_SETTINGCHANGE:
begin
//Handler code
end;
end;
Result := False; //continue processing
end;
You handle it just like you would any other message. TApplication's default handler will route it correctly if you set up a message handler for it:
// interface
type
TYourMainForm = class(TForm)
// other stuff
private
procedure WMSettingChange(var Msg: TWMSettingChange); message WM_SETTINGCHANGE;
end;
// implementation
procedure TYourMainForm.WMSettingChange(var Msg: TWMSettingChange); message WM_SETTINGCHANGE;
begin
// Whatever handling here. TWMSettingChange is defined in Messages.pas
end;