Доступ и наследование сообщений Windows для других сообщений Windows в Delphi

Я использую сообщения WMSysCommand для изменения поведения кнопки панели заголовка (развернуть / свернуть) и недавнего обновления, необходимого для использования WMNCHitTest, но я не хочу разделять эти два связанных сообщения в процедурах умножения из-за длинного кода.

Могу ли я получить доступ к частной декларации (сообщению) из другого сообщения? И если я могу - Как это сделать?

  procedure TForm1.WMNCHitTest(var Msg: TWMNCHitTest) ;
  begin
    SendMessage(Handle, HTCAPTION, WM_NCHitTest, 0); // or other wParam or lParam ???? 
  end;

  procedure TForm1.WMSysCommand;
  begin
    if (Msg.CmdType = SC_MAXIMIZE or 61488) or (Msg.Result = htCaption or 2) then // if command is Maximize or reciever message of Caption Bar click
    begin
      if CheckWin32Version(6, 0) then
        Constraints.MaxHeight := 507
      else
        Constraints.MaxHeight := 499;
      Constraints.MaxWidth := 0;
    end
    else if (Msg.CmdType = SC_MINIMIZE or 61472) or (Msg.Result = htCaption or 2) then // if command is Minimize
    begin
      if (EnsureRange(Width, 252, 510) >= (510 / 2)) then
        PreviewOpn.Caption := '<'
      else
        PreviewOpn.Caption := '>';
    end;
    DefaultHandler(Msg); // reset Message handler to default ( Application )
  end;

Итак... правильно ли я думаю и просто не знаю правильных команд, или я думаю полная ерунда?

С уважением. Спасибо за любую помощь...


person HX_unbanned    schedule 14.06.2010    source источник
comment
Похоже, вопрос, который вы должны были задать, был следующим: Как мне изменить поведение кнопок панели заголовка?   -  person Rob Kennedy    schedule 14.06.2010
comment
Влл - не очень. Наиболее уместно было бы - как сымитировать WM из другой процедуры WM ..., но я не писал, так как в некотором смысле взлом предопределяет поведение ОС ... не хочу рисковать с серьезным разговором с модераторами здесь.   -  person HX_unbanned    schedule 14.06.2010


Ответы (1)


Ваш код и текст указывают на то, что у вас есть некоторые недопонимания о том, как работают обработчики сообщений. Во-первых, вы спрашиваете о доступе к обработчикам личных сообщений. Вам не нужен доступ к обработчикам личных сообщений из родительских классов. Вы можете переопределить обработчик любого сообщения, независимо от того, обрабатывает ли это сообщение родительский класс. Просто напишите свой обработчик сообщений. Он автоматически переопределит родительский обработчик, даже если родительский обработчик был закрытым. (На самом деле, именно поэтому мы часто объявляем обработчики сообщений закрытыми в первую очередь — потомки всегда могут их переопределить, а поскольку нет причин вызывать их напрямую, нет причин и делать их общедоступными.)

Похоже, вы пытаетесь получить поведение обработки сообщений базового класса, вызывая DefaultHandler. Иногда это срабатывает, но только случайно. DefaultHandler переходит к обработчику сообщений базового класса. Если между базовым классом и вашим потомком есть другие классы, вызов DefaultHandler пропустит их обработчики. Вместо этой функции используйте директиву inherited, как при переопределении обычных методов.

Если вы хотите, чтобы ваш объект вел себя как если бы ему было отправлено сообщение, вам не всегда нужно отправлять ему сообщение с SendMessage. Вместо этого вы можете вызвать метод Perform объекта. Будут выполняться все те же операции отправки сообщений, но вы можете пропустить очередь сообщений Windows.

Если у вас есть два метода, которые должны выполнять много похожих задач, у вас есть несколько вариантов:

  1. Скопируйте и вставьте код, чтобы обе функции выглядели одинаково.
  2. Поместите весь код в одну функцию, а затем вызовите ее из второй функции.
  3. Поместите весь код в новую, третью функцию, а затем вызовите ее из обеих функций.

Первый вариант обычно не является хорошей идеей. Второй вариант может быть хорош, если гарантировано, что первая функция всегда будет подмножеством второй функции. Однако, если ей нужно сделать что-то, чего вторая функция не всегда хочет, то не следует вызывать ее из второй функции. Третий вариант — это то, что Роберта ответ предполагает.

Второй вариант может быть тем, что вам нужно, если мой хрустальный шар работает правильно. Я думаю, вы хотите, чтобы ваш обработчик wm_SysCommand выполнял проверку попадания, поэтому вы хотите вызвать обработчик сообщений wm_NCHitTest. Это легко.

procedure TForm1.WMSysCommand;
var
  Hit: DWord;
begin
  Hit := Perform(wm_NCHitTest, ...);
  if (Msg.CmdType = SC_MAXIMIZE) or (Hit = htCaption) then // if command is Maximize or reciever message of Caption Bar click
  begin
    if CheckWin32Version(6, 0) then
      Constraints.MaxHeight := 507
    else
      Constraints.MaxHeight := 499;
    Constraints.MaxWidth := 0;
  end
  else if (Msg.CmdType = SC_MINIMIZE) or (Hit = htCaption) then // if command is Minimize
  begin
    if (EnsureRange(Width, 252, 510) >= (510 / 2)) then
      PreviewOpn.Caption := '<'
    else
      PreviewOpn.Caption := '>';
  end;
  inherited;
end;

Обратите внимание на несколько изменений, которые я внес в ваш код. Во-первых, я использую Perform для вызова обработчика wm_NCHitTest объекта и сохраняю результат в переменной. Я использую эту переменную в следующих условиях, чтобы проверить, где была нажата мышь. Во-вторых, я удалил or тестов из ваших условий. Вы комбинировали именованные константы с их числовыми эквивалентами, что бессмысленно и сбивает с толку. В-третьих, я заменил вызов DefaultHandler на вызов inherited.

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

person Rob Kennedy    schedule 14.06.2010
comment
Роб, если вы хотите, чтобы ваш объект вел себя так, как если бы ему было отправлено сообщение, вам не всегда нужно отправлять ему сообщение с помощью SendMessage. (...) Но что произойдет, если я использую его в цикле с командой ProcessMessages? Разве это не означает, что Perform() фактически будет действовать как эксклюзивный SendMesssage()? О, и числовое равенство просто для меня, чтобы запомнить эти чертовы числа для внутренней и внешней обработки исключений и обработки WER ... На самом деле - я всегда могу проверить код ключей с помощью Ord(), поэтому я не думаю, что это будет большой проблемой. - person HX_unbanned; 14.06.2010
comment
ProcessMessages не имеет к этому никакого отношения. Perform также полезен для вызова обработчиков сообщений для объектов, не имеющих оконных дескрипторов. - person Rob Kennedy; 14.06.2010