首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 編寫 Windows Shell 擴展:Context Menu Handler 實現右鍵選單「檔案操作」完整開發指南

     編輯:Delphi

Shell 擴展基礎

  • 基於 COM (Component Object Model),以 DLL 形式載入 explorer.exe 進程
  • 7 種 Handler:Context Menu、Drag&Drop、Icon、Property Sheet、Copy Hook、Drop Target、Data Object
  • 需註冊至 HKCR\CLSID\{GUID}、HKCR\*\shellex\ContextMenuHandlers、NT 系統額外 Approved 列表
  • 使用 regsvr32.exe 或 Delphi Run → Register ActiveX Server 註冊

Context Menu Handler 介面

必須實作三個介面:

  • IShellExtInit:初始化,取得使用者選取的檔案清單
  • IContextMenu:建構右鍵選單項目、處理點擊命令、提供說明文字
  • IComObjectFactory:COM 物件工廠 (Delphi TComObjectFactory 封裝)

專案結構

  • ContextMenu.dpr:DLL 專案,匯出 DllGetClassObject、DllCanUnloadNow、DllRegisterServer、DllUnregisterServer
  • ContextMenuHandle.pas:核心 COM 物件實作
  • OpWindow.pas:檔案操作視窗表單 (ListBox + Copy/Move 按鈕)

關鍵實作細節

IShellExtInit.Initialize:取得選取檔案


function TContextMenu.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult;
var
  StgMedium: TStgMedium;
  FormatEtc: TFormatEtc;
  FileCount, I: Integer;
begin
  if lpdobj = nil then Exit(E_INVALIDARG);
  FileList := TStringList.Create; FileList.Clear;
  FormatEtc.cfFormat := CF_HDROP; // 檔案拖放格式
  FormatEtc.ptd := nil; FormatEtc.dwAspect := DVASPECT_CONTENT;
  FormatEtc.lindex := -1; FormatEtc.tymed := TYMED_HGLOBAL;
  Result := lpdobj.GetData(FormatEtc, StgMedium);
  if Failed(Result) then Exit;
  FileCount := DragQueryFile(StgMedium.hGlobal, $FFFFFFFF, nil, 0);
  for I := 0 to FileCount - 1 do begin
    DragQueryFile(StgMedium.hGlobal, I, FFileName, SizeOf(FFileName));
    FileList.Add(FFileName);
  end;
  ReleaseStgMedium(StgMedium);
  Result := NOERROR;
end;

IContextMenu.QueryContextMenu:加入選單項目


function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult;
begin
  Result := 0;
  if ((uFlags and $0000000F) = CMF_NORMAL) or ((uFlags and CMF_EXPLORE) <> 0) then begin
    InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst, '檔案操作');
    Result := 1; // 回傳新增項目數
  end;
end;

IContextMenu.InvokeCommand:執行命令


function TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
var
  Frm: TForm1;
begin
  if HiWord(Integer(lpici.lpVerb)) <> 0 then Exit(E_FAIL); // 非選單命令
  if LoWord(lpici.lpVerb) <> 0 then Exit(E_INVALIDARG);   // 非第一個命令
  Frm := TForm1.Create(nil);
  Frm.ListBox1.Items := FileList; // 傳遞檔案清單
  Result := NOERROR;
end;

IContextMenu.GetCommandString:狀態列提示


function TContextMenu.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HRESULT;
begin
  if (idCmd = 0) and (uType = GCS_HELPTEXT) then begin
    StrCopy(pszName, '點擊該選單項將執行檔案操作');
    Result := NOERROR;
  end else Result := E_INVALIDARG;
end;

註冊/反註冊邏輯


procedure TContextMenuFactory.UpdateRegistry(Register: Boolean);
var ClassID: string;
begin
  if Register then begin
    inherited UpdateRegistry(Register);
    ClassID := GUIDToString(Class_ContextMenu);
    CreateRegKey('*\shellex', '', '');
    CreateRegKey('*\shellex\ContextMenuHandlers', '', '');
    CreateRegKey('*\shellex\ContextMenuHandlers\FileOperation', '', ClassID);
    if Win32Platform = VER_PLATFORM_WIN32_NT then
      with TRegistry.Create do try
        RootKey := HKEY_LOCAL_MACHINE;
        OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved', True);
        WriteString(ClassID, 'Context Menu Shell Extension');
      finally Free; end;
  end else begin
    DeleteRegKey('*\shellex\ContextMenuHandlers\FileOperation');
    inherited UpdateRegistry(Register);
  end;
end;

檔案操作視窗實作


procedure TForm1.Button1Click(Sender: TObject); // 複製
var
  Path: string;
  FS: SHFILEOPSTRUCT;
  I: Integer;
begin
  Path := InputBox('檔案操作', '輸入複製路徑', 'C:\Windows');
  if Path <> '' then
    for I := 0 to ListBox1.Items.Count - 1 do begin
      FillChar(FS, SizeOf(FS), 0);
      FS.Wnd := Handle;
      FS.wFunc := FO_COPY;
      FS.fFlags := FOF_ALLOWUNDO;
      FS.pFrom := PChar(ListBox1.Items[I] + #0); // 雙重 Null 結尾
      FS.pTo := PChar(Path + #0);
      FS.lpszProgressTitle := '複製檔案';
      if SHFileOperation(FS) <> 0 then ShowMessage('複製失敗');
    end;
end;

建置與部署

  1. Project → Build ContextMenu 產生 ContextMenu.dll
  2. 管理員權限執行:regsvr32 ContextMenu.dll
  3. 資源管理器右鍵任意檔案/資料夾 → 出現「檔案操作」選單

現代替代方案

  • IExplorerCommand (Win7+):更簡單、支援功能區、非 COM 掛載
  • 應用程式註冊:HKCR\*\shell\YourCommand + command 值指向 EXE 參數 %1,無需 DLL 注入

總結

Shell Context Menu Handler 是經典 COM 技術展示。完整實作涵蓋 IShellExtInit 初始化取檔 → IContextMenu 構建選單/執行/提示 → COM Factory 註冊。雖現代 Windows 推薦輕量替代方案,但理解此架構對維護舊系統、深度整合 Explorer 仍具不可替代價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved