Одним из багов, который вылез сразу при нашей первой попытке показать меню - пункты "Открыть с помощью" и "Отправить" не работают.
Причина в том, что эти подменю имеют отложенное создание (что объясняет, почему они пустые, когда вы разворачиваете их) и 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).
Запустите пример с этими изменениями и заметьте, что пункты меню "Открыть с помощью" и "Отправить" теперь работают, как ожидалось.
В следующий раз: получение подсказок к пунктам меню.
А что это за модуль такой - JwaShlObj (судя по всему он нужен для IID_IContextMenu3)? Если я не ошибаюсь надо ставить JEDI?
ОтветитьУдалитьJWA-модуля - это заголовочники JEDI.
ОтветитьУдалитьOK, спасиба за ссылку.
ОтветитьУдалить