воскресенье, 9 августа 2009 г.

Как управлять IContextMenu, часть 5 - обработка сообщений от меню

Это перевод How to host an IContextMenu, part 5 - Handling menu messages. Автор: Реймонд Чен.

Одним из багов, который вылез сразу при нашей первой попытке показать меню - пункты "Открыть с помощью" и "Отправить" не работают.

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

Вот тут и используются методы IContextMenu2.HandleMenuMsg и IContextMenu3.HandleMenuMsg2.

Историческое примечание: метод IContextMenu2.HandleMenuMessage находится в своём собственном интерфейсе, а не в базовом IContextMenu, потому что он был поздно добавлен при разработке Windows 95, поэтому решили, что безопаснее объявить новый интерфейс, чем заставить всех, кто писал расширения оболочки Windows 95, переписывать свой код. Метод IContextMenu3.HandleMenuMessage2 был добавлен в Internet Explorer 4 (мне кажется), когда стало ясно, что способность расширителя контекстного меню переопределять возвращаемое значение обработчика сообщения была необходимой для поддержки keyboard accessibility в контекстных меню owner-drawn.

uses
..., ActiveX, JwaShlObj;

type
TForm1 = class(TForm)
...
private
{ Private declarations }
g_pcm2: IContextMenu2;
g_pcm3: IContextMenu3;
end;

Эти две новые переменные отслеживают интерфейсы IContextMenu2 и IContextMenu3 активного всплывающего меню. Нам нужно инициализировать и очистить их вокруг нашего вызова TrackPopupMenuEx:

        Pcm.QueryInterface(IID_IContextMenu2, g_pcm2);
Pcm.QueryInterface(IID_IContextMenu3, g_pcm3);
try
iCmd := Integer(TrackPopupMenuEx(Menu, TPM_RETURNCMD, Pt.X, Pt.y, Handle, nil));
finally
g_pcm3 := nil;
g_pcm2 := nil;
end;

И, наконец, нам нужно вызывать методы HandleMenuMsg/HandleMenuMsg2 в оконной процедуре:

type
TForm1 = class(TForm)
...
protected
{ Protected declarations }
procedure WndProc(var Message: TMessage); override;
end;

procedure TForm1.WndProc(var Message: TMessage);
begin
if Assigned(g_pcm3) then
begin
if SUCCEEDED(g_pcm3.HandleMenuMsg2(Message.Msg, Message.wParam, Message.lParam, Message.Result)) then
Exit;
end
else
if Assigned(g_pcm2) then
if SUCCEEDED(g_pcm2.HandleMenuMsg(Message.Msg, Message.wParam, Message.lParam)) then
begin
Message.Result := 0;
Exit;
end;
inherited;
end;

В оконной процедуры мы спрашиваем контекстное меню, хочет ли оно обработать сообщение. Если да, то мы останавливаем обработку и возвращаем нужное значение (для HandleMenuMsg2) или просто 0 (для HandleMenuMsg).

Запустите пример с этими изменениями и заметьте, что пункты меню "Открыть с помощью" и "Отправить" теперь работают, как ожидалось.

В следующий раз: получение подсказок к пунктам меню.

3 комментария:

  1. А что это за модуль такой - JwaShlObj (судя по всему он нужен для IID_IContextMenu3)? Если я не ошибаюсь надо ставить JEDI?

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.