Delphi: Как ответить на WM_SettingChange / WM_WinIniChange? - PullRequest
3 голосов
/ 12 мая 2010

Мне нужно знать, когда мое приложение получит сообщение WM_SETTINGCHANGE (ранее известное как WM_WININICHANGE).

Проблема в том, что насос сообщений в TApplication отправляет его в черную дыру (обработчик по умолчанию), прежде чем я могу получить шанс увидеть его:

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;

Процедура CheckIniChange() не генерирует ни одного события, которое я могу обработать, и Mouse.SettingChanged().

И как только путь кода достигает Default, он отправляется по сливному отверстию DefWindowProc, и его больше никогда не увидеть (поскольку первое, что делает WndProc, устанавливает Message.Result на ноль.

Я надеялся назначить обработчик для события TApplicationEvents.OnMessage:

procedure TdmGlobal.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
   case Msg.message of
   WM_SETTINGCHANGE:
      begin
         // Code
      end;
   end;
end;

Но событие OnMessage генерируется только для сообщений, поступающих через насос сообщений. Так как сообщение WM_SETTINGCHANGE обработано, оно никогда не увидит

PeekMessage
TranslateMessage
DispatchMessage

система.

Как мне ответить на трансляцию Windows WM_SETTINGCHANGE?

Ответы [ 3 ]

9 голосов
/ 12 мая 2010

Edit2: для старых версий обычный перехват сообщений должен работать ...

[...]
  private
    procedure WMSettingChange(var Message: TWMSettingChange); message WM_SETTINGCHANGE;
[...]
procedure TForm1.WMSettingChange(var Message: TWMSettingChange);
begin
  showMessage('SettingChange message intercept');
end;

Редактировать: Упс! Не видел, это было для D5. Следующее было в D2007 +.

Используйте OnSettingChange в своем приложении:

procedure TApplication.SettingChange(var Message: TWMSettingChange);
begin
  if Assigned(FOnSettingChange) then
    with Message do
      FOnSettingChange(Self, Flag, Section, Result);
end;

Вы можете проверить с помощью этого кода. Попробуйте изменить высоту или сторону панели задач ...

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;
2 голосов
/ 12 мая 2010

Вы обрабатываете это так же, как и любое другое сообщение. Обработчик по умолчанию TApplication будет правильно маршрутизировать его, если вы настроите для него обработчик сообщений:

// 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;
2 голосов
/ 12 мая 2010

Ответ был на мой вопрос, опасное, недокументированное, использование 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;
...