Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Как показать контекстное меню для конкретного файла?

01.01.2007
////////////////////////////////////////////////////////////////////////////////
//
//  ****************************************************************************
//  * Unit Name : Unit1
//  * Purpose   : Демо отображения системного контекстного меню эксплорера
//  * Author    : Александр (Rouse_) Багель
//  * Version   : 1.00
//  ****************************************************************************
//
 
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,
  // Чтоб все заработало - подключаем вот эти 2 юнита
  ShlObj,
  ActiveX;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
// Это для работы самого меню, как оконного элемента
function MenuCallback(Wnd: HWND; Msg: UINT; WParam: WPARAM;
 LParam: LPARAM): LRESULT; stdcall;
var
  ContextMenu2: IContextMenu2;
begin
  case Msg of
    WM_CREATE:
    begin
      ContextMenu2 := IContextMenu2(PCreateStruct(lParam).lpCreateParams);
      SetWindowLong(Wnd, GWL_USERDATA, Longint(ContextMenu2));
      Result := DefWindowProc(Wnd, Msg, wParam, lParam);
    end;
    WM_INITMENUPOPUP:
    begin
      ContextMenu2 := IContextMenu2(GetWindowLong(Wnd, GWL_USERDATA));
      ContextMenu2.HandleMenuMsg(Msg, wParam, lParam);
      Result := 0;
    end;
    WM_DRAWITEM, WM_MEASUREITEM:
    begin
      ContextMenu2 := IContextMenu2(GetWindowLong(Wnd, GWL_USERDATA));
      ContextMenu2.HandleMenuMsg(Msg, wParam, lParam);
      Result := 1;
    end;
  else
    Result := DefWindowProc(Wnd, Msg, wParam, lParam);
  end;
end;
 
// Это для создания самого меню, как оконного элемента
function CreateMenuCallbackWnd(const ContextMenu: IContextMenu2): HWND;
const
  IcmCallbackWnd = 'ICMCALLBACKWND';
var
  WndClass: TWndClass;
begin
  FillChar(WndClass, SizeOf(WndClass), #0);
  WndClass.lpszClassName := PChar(IcmCallbackWnd);
  WndClass.lpfnWndProc := @MenuCallback;
  WndClass.hInstance := HInstance;
  Windows.RegisterClass(WndClass);
  Result := CreateWindow(IcmCallbackWnd, IcmCallbackWnd, WS_POPUPWINDOW, 0,
    0, 0, 0, 0, 0, HInstance, Pointer(ContextMenu));
end;
 
procedure GetProperties(Path: String; MousePoint: TPoint; WC: TWinControl);
var
  CoInit, AResult: HRESULT;
  CommonDir, FileName: String;
  Desktop, ShellFolder: IShellFolder;
  pchEaten, Attr: Cardinal;
  PathPIDL: PItemIDList;
  FilePIDL: array [0..1] of PItemIDList;
  ShellContextMenu: HMenu;
  ICMenu: IContextMenu;
  ICMenu2: IContextMenu2;
  PopupMenuResult: BOOL;
  CMD: TCMInvokeCommandInfo;
  M: IMAlloc;
  ICmd: Integer;
  CallbackWindow: HWND;
begin
  // Первичная инициализация
  ShellContextMenu := 0;
  Attr := 0;
  PathPIDL := nil;
  CallbackWindow := 0;
  CoInit := CoInitializeEx(nil, COINIT_MULTITHREADED);
  try
    // Получаем пути и имя фала
    CommonDir := ExtractFilePath(Path);
    FileName := ExtractFileName(Path);
    // Получаем указатель на интерфейс рабочего стола
    if SHGetDesktopFolder(Desktop) <> S_OK then
      RaiseLastOSError;
    // Если работаем с папкой
    if FileName = '' then
    begin
      // Получаем указатель на папку "Мой компьютер"
      if (SHGetSpecialFolderLocation(0, CSIDL_DRIVES, PathPIDL) <> S_OK) or
        (Desktop.BindToObject(PathPIDL,  nil,  IID_IShellFolder,
          Pointer(ShellFolder)) <> S_OK) then RaiseLastOSError;
      // Получаем указатель на директорию
      ShellFolder.ParseDisplayName(WC.Handle, nil, StringToOleStr(CommonDir),
        pchEaten, FilePIDL[0], Attr);
      // Получаем указатель на контектсное меню папки
      AResult := ShellFolder.GetUIObjectOf(WC.Handle, 1, FilePIDL[0],
        IID_IContextMenu, nil, Pointer(ICMenu));
    end
    else
    begin
      // Получаем указатель на папку "Мой компьютер"
      if (Desktop.ParseDisplayName(WC.Handle, nil, StringToOleStr(CommonDir),
        pchEaten, PathPIDL, Attr) <> S_OK) or
        (Desktop.BindToObject(PathPIDL, nil, IID_IShellFolder,
          Pointer(ShellFolder)) <> S_OK) then RaiseLastOSError;
      // Получаем указатель на файл
      ShellFolder.ParseDisplayName(WC.Handle, nil, StringToOleStr(FileName),
        pchEaten, FilePIDL[0], Attr);
      // Получаем указатель на контектсное меню файла
      AResult := ShellFolder.GetUIObjectOf(WC.Handle, 1, FilePIDL[0],
        IID_IContextMenu, nil, Pointer(ICMenu));
    end;
 
    // Если указатель на конт. меню есть, делаем так:
    if Succeeded(AResult) then
    begin
      ICMenu2 := nil;
      // Создаем меню
      ShellContextMenu := CreatePopupMenu;
      // Производим его наполнение
      if Succeeded(ICMenu.QueryContextMenu(ShellContextMenu, 0,
        1, $7FFF, CMF_EXPLORE)) and
        Succeeded(ICMenu.QueryInterface(IContextMenu2, ICMenu2)) then
          CallbackWindow := CreateMenuCallbackWnd(ICMenu2);
      try
        // Показываем меню
        PopupMenuResult := TrackPopupMenu(ShellContextMenu, TPM_LEFTALIGN or TPM_LEFTBUTTON
          or TPM_RIGHTBUTTON or TPM_RETURNCMD,
          MousePoint.X, MousePoint.Y, 0, CallbackWindow, nil);
      finally
        ICMenu2 := nil;
      end;
      // Если был выбран какой либо пункт меню:
      if PopupMenuResult then
      begin
        // Индекс этого пункта будет лежать в ICmd
        ICmd := LongInt(PopupMenuResult) - 1;
        // Заполняем структуру TCMInvokeCommandInfo
        FillChar(CMD, SizeOf(CMD), #0);
        with CMD do
        begin
          cbSize := SizeOf(CMD);
          hWND := WC.Handle;
          lpVerb := MakeIntResource(ICmd);
          nShow := SW_SHOWNORMAL;
        end;
        // Выполняем InvokeCommand с заполненной структурой
        AResult := ICMenu.InvokeCommand(CMD);
        if AResult <> S_OK then RaiseLastOSError;
       end;
    end;
  finally
    // Освобождаем занятые ресурсы чтобы небыло утечки памяти
    if FilePIDL[0] <> nil then
    begin
      // Для освобождения использем IMalloc
      SHGetMAlloc(M);
      if M <> nil then
        M.Free(FilePIDL[0]);
      M:=nil;
    end;
    if PathPIDL <> nil then
    begin
      SHGetMAlloc(M);
      if M <> nil then
        M.Free(PathPIDL);
      M:=nil;
    end;
    if ShellContextMenu <>0 then
      DestroyMenu(ShellContextMenu);
    if CallbackWindow <> 0 then
      DestroyWindow(CallbackWindow);
    ICMenu := nil;
    ShellFolder := nil;
    Desktop := nil;
    if CoInit = S_OK then CoUninitialize;
  end;
end;
 
// Пример использования
procedure TForm1.Button1Click(Sender: TObject);
var
  pt: TPoint;
begin
  GetCursorPos(pt);
  GetProperties('E:\Guardant\INSTDRV.INI', pt, Self);
end;
 
end.

Взято из https://forum.sources.ru

Автор: Rouse_