程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Windows外殼擴展編程之添加右鍵菜單

Windows外殼擴展編程之添加右鍵菜單

編輯:Delphi

Windows外殼擴展編程  www.applevb.com
    在Windows下的一些軟件提供了這樣的功能:當安裝了這些軟件之後,當在Windows的Explore中鼠標右鍵單擊文件或者文件夾後,在彈出菜單中就會多出與該軟件操作相關的菜單項,點擊該項就會激活相應的程序對用戶選中的文件進行相應的操作。例如安裝了Winzip之後,當用戶選中一個文件夾後單擊右鍵,在彈出菜單中就會多出一個Add To Zip和一個 Add To xxx.zip的選項,其中xxx為選中的文件夾的名稱。只要單擊上面的兩個菜單項中的一個,就可以方便的壓縮目錄了。這樣的功能稱為Windows外殼擴展(Shell Extensions)
  外殼擴展概述

  下面是與外殼擴展相關的三個重要術語:
  (1)文件對象(File Object)
     文件對象是外殼中的一項,大家最熟識的文件對象是文件和目錄,此外,打印機、控制面板程序、共享網
       絡等也都是文件對象。
  (2)文件類(File Class)
       文件類是具有某種共同特性的文件對象的集合,比如,擴展名相同的文件屬於同一文件類。
  (3)處理程序(Handler)
     處理程序是具體實現某個外殼擴展的代碼。

  Windows支持七種類型的外殼擴展(稱為Handler),它們相應的作用簡述如下:
  (1)Context menu handlers向特定類型的文件對象增添上下文相關菜單;
  (2)Drag-and-drop handlers用來支持當用戶對某種類型的文件對象進行拖放操作時的OLE數據傳輸;
  (3)Icon handlers用來向某個文件對象提供一個特有的圖標,也可以給某一類文件對象指定圖標;
  (4)Property sheet handlers給文件對象增添屬性頁,屬性頁可以為同一類文件對象所共有,也可以給一個
       文件對象指定特有的屬性頁;
  (5)Copy-hook handlers在文件夾對象或者打印機對象被拷貝、移動、刪除和重命名時,就會被系統調用,
       通過為Windows增加Copy-hook handlers,可以允許或者禁止其中的某些操作;
  (6)Drop target handlers在一個對象被拖放到另一個對象上時,就會被系統被調用;
  (7)Data object handlers在文件被拖放、拷貝或者粘貼時,就會被系統被調用。

  Windows的所有外殼擴展都是基於COM(Component Object Model) 組件模型的,外殼是通過接口(Interface)來訪問對象的。外殼擴展被設計成32位的進程中服務器程序,並且都是以動態鏈接庫的形式為操作系統提供服務的。因此,如果要對Windows的用戶界面進行擴充的話,則具備寫COM對象的一些知識是十分必要的。

  寫好外殼擴展程序後,必須將它們注冊才能生效。所有的外殼擴展都必須在Windows注冊表的HKEY_CLASSES_ROOTCLSID鍵之下進行注冊。在該鍵下面可以找到許多名字像{0000002F-0000-0000-C000-000000000046}的鍵,這類鍵就是全局唯一類標識符。每一個外殼擴展都必須有一個全局唯一類標識符,Windows正是通過此唯一類標識符來找到外殼擴展處理程序的。在類標識符之下的InProcServer32子鍵下記錄著外殼擴展動態鏈接庫在系統中的位置。與某種文件類型關聯的外殼擴展注冊在相應類型的shellex主鍵下。如果所處的Windows操作系統為Windows NT,則外殼擴展還必須在注冊表中的HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionShellExtensionsApproved主鍵下登記。

  注冊表HKEY_CLASSES_ROOT主鍵下有幾個特殊的子鍵,如*、Folder、Drive以及Printer。如果把外殼擴展注冊在*子鍵下,那麼這個外殼擴展將對Windows中所有類型的文件有效;如果把外殼擴展注冊在Folder子鍵下,則對所有目錄有效。

    上面提到的在Windows Explore中在鼠標右鍵菜單中添加菜單項(我們成為上下文相關菜單)的操作屬於外殼擴展的第一類,即Context menu handlers向特定類型的文件對象增添上下文相關菜單。要動態地在上下文相關菜單中增添菜單項,可以通過寫Context Menu Handler來實現。
  編寫Context Menu Handler必須實現IShellExtInit和IContextMenu兩個接口。除了IUnknown接口所定義的函數之外,Context Menu Handler還需要用到QueryContextMenu、InvokeCommand和GetCommandString這三個非常重要的成員函數。

  (1)QueryContextMenu函數:每當系統要顯示一個文件對象的上下文相關菜單時,它首先要調用該函數。為了在上下文相關菜單中添加菜單
 項,我們在該函數中調用InsertMenu函數。

  (2)InvokeCommand函數:當用戶選定了某個Context Menu Handler登記過的菜單項後,該函數將會被調用,系統將會傳給該函數一個指向
 LPCMINVOKECOMMANDINFO結構的指針。在該函數中要執行與所選菜單項相對應的操作。

  (3)GetCommandString函數:當鼠標指針移到一個上下文相關菜單項上時,在當前窗口的狀態條上將會出現與該菜單項相關的幫助信息,此
 信息就是系統通過調用該函數獲取的。

    下面我通過具體的例程來說明編寫一個比較完整的上下文菜單程序,這個程序是一個文件操作程序,當安裝並注冊了外殼擴展的服務器動態連接庫之後,當選擇一個或者多個文件並單擊鼠標右鍵後,在右鍵菜單中就會多出一個“執行文件操作”的上下文菜單,點擊菜單就會彈出相應的程序執行文件操作。
    在整個程序的編寫中,外殼擴展的服務器動態連接庫是有Delphi4.0編寫的,而動態連接庫調用的文件操作程序是由VB6編寫的。下面首先介紹服務器動態連接庫的編寫:
    服務器動態連接庫的工程文件內容如下:

library contextmenu;
    uses
ComServ,
  ContextMenuHandler in Unit2.pas;
//   contmenu_TLB in contmenu_TLB.pas;

exports
   DllGetClassObject,
   DllCanUnloadNow,
   DllRegisterServer,
   DllUnregisterServer;

{$R *.TLB}

{$R *.RES}

begin

end.

    將工程文件保存為contextmenu.dpr。
    服務器動態連接庫的單位文件內容如下:   

unit ContextMenuHandler;

interface
   uses Windows,ActiveX,ComObj,ShlObj,Classes;

type
   TContextMenu = class(TComObject,IShellExtInit,IContextMenu)
   private
      FFileName: array[0..MAX_PATH] of Char;
   protected
      function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning
      function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
               hKeyProgID: HKEY): HResult; stdcall;
      function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,
               uFlags: UINT): HResult; stdcall;
      function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
      function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
               pszName: LPSTR; cchMax: UINT): HResult; stdcall;
end;

const

   Class_ContextMenu: TGUID = {19741013-C829-11D1-8233-0020AF3E97A9};

{全局唯一標識符(GUID)是一個16字節(128為)的值,它唯一地標識一個接口(interface)}
var
   FileList:TStringList;
   Buffer:array[1..1024]of char;

implementation

uses ComServ, SysUtils, ShellApi, Registry,UnitForm;

function TContextMenu.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
   hKeyProgID: HKEY): HResult;
var
   StgMedium: TStgMedium;
   FormatEtc: TFormatEtc;
   FileNumber,i:Integer;
begin
   file://如果lpdobj等於Nil,則本調用失敗
   if (lpdobj = nil) then begin
      Result := E_INVALIDARG;
      Exit;
   end;

   file://首先初始化並清空FileList以添加文件
   FileList:=TStringList.Create;
   FileList.Clear;
   file://初始化剪貼版格式文件
   with FormatEtc do begin
      cfFormat := CF_HDROP;
      ptd := nil;
      dwAspect := DVASPECT_CONTENT;
      lindex := -1;
      tymed := TYMED_HGLOBAL;
   end;
   Result := lpdobj.GetData(FormatEtc,

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved