Re: контекстное меню "открыть с помощью"
От: Slicer [Wirkwood] Россия https://ru.linkedin.com/in/maksim-gumerov-039a701b
Дата: 24.02.03 09:03
Оценка:
На выбор — два похожих решения. Боюсь, ни одно из них полностью Вас не устроит, хотя — может, пойдет и так
Первый вариант — просто вывести сразу окошко 'Открыть с помощью', без меню. В WinXP оно довольно мощное.
Второй — вывести целиком все предлагаемое Explorer контекстное меню. Как отфильтровать конкретно подменю "Открыть с помошью", с учетом того, что Win может быть локализованным, — не знаю. Есть мысль после вызова QueryContextMenu найти в меню такое подменю (WinAPI GetSubMenu), в котором есть опция, которой соответствует canonical verb 'openas' (см. IContextMenu::GetCommandString), и выводить только это подменю. Если такого подменю нет, то 'openas' соответствует какой-то команде из самого контекстного меню, и ее можно отыскать опять же при помощи GetCommandString. Остальные элементы меню можно удалить

Ну, и собственно код:

//Uses ShlObj, ComObj, Windows;
procedure TForm1.Button1Click(Sender: TObject);
var
    L:IShellLink;
    CM:IContextMenu2; //Если надо отображать меню, то CM должна быть видима из TForm1
    //(т.е. надо переместить объявление туда или вообще сделать CM глобальной)
    IKI:_CMINVOKECOMMANDINFO;
    Menu:HMenu;
begin
  L:=CreateComObject(ProgIDToClassID('lnkfile')) as IShellLink;
  L.SetPath('c:\image1.jpg'); //Поставьте сюда имя нужного Вам файла
  CM:=L as IContextMenu2;

  Menu:=CreatePopupMenu;
  CM.QueryContextMenu(Menu,0,0,$7fff,0); //Опрос меню нужен обязательно
  L:=nil;

  //Это - если запускаем окно Open As сразу, без отображения меню:
  IKI.cbSize:=sizeof(IKI);
  IKI.hwnd:=self.Handle;
  IKI.fMask:=0;
  IKI.lpVerb:=pchar('openas'); // Вот canonical verb, о котором я говорил
  IKI.lpParameters:=pchar('c:\image1.jpg');
  IKI.lpDirectory:=nil;
  IKI.nShow:=SW_SHOWNORMAL;
  CM.InvokeCommand(IKI);
  CM:=nil; //Оно больше не надо

// Код для инициации отображения:
//  P:=Button1.ClientToScreen(Point(Button1.Width,Button1.Height));
//  TrackPopupMenu(Menu,0, P.X, P.y, 0, handle, 0);

  //Ну и убиваем меню
  DestroyMenu(Menu);
end;


Если меню надо отображать, то придется еще добавить:

//В TForm1:
    procedure WMCommand(var M:TWMCommand);message WM_COMMAND;
    procedure WndProc(var Message:TMessage); override;

//Реализация:
procedure TForm1.WndProc(var Message: TMessage);
begin
  if (Message.Msg = WM_INITMENUPOPUP) or
     (Message.Msg = WM_MENUCHAR) or
     (Message.Msg = WM_DRAWITEM) or
     (Message.Msg = WM_MEASUREITEM) then CM.HandleMenuMsg(Message.Msg,Message.WParam,Message.LParam)
  else
    inherited;
end;

procedure TForm1.WMCommand(var M: TWMCommand);
var
    IKI:_CMINVOKECOMMANDINFO;
begin
  if M.Ctl<>0 then inherited
  else
  begin
    IKI.cbSize:=sizeof(IKI);
    IKI.hwnd:=self.Handle;
    IKI.fMask:=0;
    IKI.lpVerb:=pchar(M.ItemID);
    IKI.lpParameters:=nil;
    IKI.lpDirectory:=nil;
    IKI.nShow:=SW_SHOWNORMAL;
    CM.InvokeCommand(IKI);
  end;
end;


С уважением, Slicer
Специалист — это варвар, невежество которого не всесторонне :)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.