利用Windows外殼擴充套件保護資料夾 (轉)

worldblog發表於2007-12-04
利用Windows外殼擴充套件保護資料夾 (轉)[@more@]

利用外殼擴充套件保護夾
在操作(包括、、)不但有方便的圖形(GUI)介面,還為windows使用者介面保留了強大的可擴充性。其中對於Windows介面的操作環境(這裡稱為外殼),微軟提供了一種稱為外殼擴充套件(Shell Extensions)的功能來實現檔案系統操作的可性。如果你的機器中了 7.0以上的版本,當你滑鼠右鍵單擊一個DOC檔案,在彈出選單中選“屬性”項,在屬性頁中不僅顯示顯示檔案的大小、建立日期等資訊,同時還增加了Doc文件的摘要、統計等資訊;又例如安裝了 6.0以上版本後,當選中一個或多個檔案或資料夾後在單擊滑鼠右鍵,在彈出的右鍵選單中就增加了“Add To Zip”等一個zip檔案選項。上面的這些功能都是透過Windows外殼擴充套件來實現的。
Windows外殼擴充套件是這樣實現的。首先要編寫外殼擴充套件,一個外殼擴充套件程式是基於COM(Component Model)模型的。外殼是透過介面(Interface)來訪問的。外殼擴充套件被設計成32位的程式中程式,並且都是以動態連結庫的形式為提供服務的。
寫好外殼擴充套件程式後,必須將它們註冊才能生效。所有的外殼擴充套件都必須在Windows登錄檔的HKEY_CLASSES_CLSID鍵之下進行註冊。在該鍵下面可以找到許多名字像{ACDE002F-0000-0000-C000-000000000046}的鍵,這類鍵就是全域性唯一類識別符號。每一個外殼擴充套件都必須有一個全域性唯一類識別符號,Windows正是透過此唯一類識別符號來找到外殼擴充套件處理程式的。在類識別符號之下的InProcServer32子鍵下記錄著外殼擴充套件動態連結庫在系統中的位置。

Windows系統支援以下7類的外殼擴充套件功能:
(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在檔案被拖放、複製或者貼上時,就會被系統被呼叫。
本文介紹的資料夾保護功能就是透過上面的第5類,既Copy-hook handlers來實現的。一個支援Copy-hook handlers的程式除了上面提到的要在登錄檔的HKEY_CLASSES_ROOTCLSID下注冊之外,還需要在HKEY_CLASSES_ROOTDirectoryshellexCopyHookHandlers下注冊伺服器程式的類。
由於Windows外殼伺服器程式是基於COM元件模型的,所以編寫外殼程式就是構造一個COM物件的過程,由於4.0以上的版本支援Windows外殼擴充套件和COM元件模型,所以可以利用Delphi來編寫外殼擴充套件程式。
利用Delphi編寫Copy-hook handle需要實現ICopyHook介面。ICopyHook是一個十分簡單的介面,要實現的只有CopyCallBack方法。ICopyHook的CopyCallBack方法的定義如下:
UINT CopyCallback(
  HWND hwnd,  of the parent window for displaying UI objects
  UINT wFunc,  to perform.
  UINT wFlags,  that control the operation
  LPCSTR pszSrcFile,  to the file
  DWORD dwSrcAttribs,  file attributes
  LPCSTR pszDestFile,  to the destination file
  DWORD dwDestAttribs  file attributes
  );
其中的引數hwnd是一個視窗控制程式碼,Copy-hook handle以此為父視窗。引數wFunc指定要被的操作,其取值為下表中所列之一:
常量 取值 含義
FO_COPY $2 複製由pszSrcFile指定的檔案到由pszDestFile指定的位置。
FO_DELETE $3 刪除由pszSrcFile指定的檔案。
FO_MOVE $1 移動由pszSrcFile指定的檔案到由pszDestFile指定的位置。
FO_RENAME $4 重新命名由pszSrcFile指定的檔案到由pszDestFile指定的檔名。
PO_DELETE $13 刪除pszSrcFile指定的印表機。
PO_PORTCHANGE $20 改變印表機埠。PszSrcFile和pszDestFile為兩個以Null結尾的字串,分別指定當前和新的印表機埠名。
PO_RENAME $14 重新命名由pszSrcFile指定的印表機埠。
PO_REN_PORT $34 PO_RENAME和PO_PORTCHANGE的組合。

 引數wFlags指定操作的標誌;引數pszSrcFile和pszDestFile指定原始檔夾和目標資料夾。引數dwSrcAttribs和dwDesAttribs指定原始檔夾和目標資料夾的屬性。返回值可以為IDYES、IDNO和IDCANCEL。分別指示Windows外殼允許操作、阻止操作,但是其他操作繼續、阻止當前操作,取消為執行的操作。
 下面是具體的程式實現:
 首先在Delphi的選單中選 File|New選項,選擇其中的DLL圖示,按Ok鍵建立一個DLL工程檔案,在其中新增以下程式碼:
library CopyHook;

uses
  ComServ,
  CopyMain in 'CopyMain.pas';

exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;

{$R *.TLB}

{$R *.RES}

begin
end.
將檔案儲存為 CopyHook.dpr。再在Delphi選單中選File|New選項,選擇其中的Unit圖示,按Ok鍵建立一個Pas檔案,在其中加入以下程式碼:
unit CopyMain;

interface

uses Windows, ComObj, ShlObj;

type
  TCopyHook = class(TComObject, ICopyHook)
  protected
  function CopyCallback(Wnd: HWND; wFunc, wFlags: UINT; pszSrcFile: PAnsiChar;
  dwSrcAttribs: DWORD; pszDestFile: PAnsiChar; dwDestAttribs: DWORD): UINT; stdcall;
  end;

  TCopyHookFactory = class(TComObjectFactory)
  protected
  function GetProgID: string; overr;
  procedure ApproveShellExtension(Register: Boolean; const ClsID: string);
  virtual;
  public
  procedure UpdateRegistry(Register: Boolean); override;
  end;

implementation

uses ComServ, SysUtils, Registry;

{ TCopyHook }

Windows外殼程式執行資料夾或者印表機埠操作時,CopyCallBack
法就會被呼叫。
function TCopyHook.CopyCallback(Wnd: HWND; wFunc, wFlags: UINT;
  pszSrcFile: PAnsiChar; dwSrcAttribs: DWORD; pszDestFile: PAnsiChar;
  dwDestAttribs: DWORD): UINT;
const
  FO_COPY = 2;
  FO_DELETE = 3;
  FO_MOVE = 1;
  FO_RENAME = 4;
var
  sOp:string;
begin
  Case wFunc of
  FO_COPY:  sOp:=format('你確定要將 %s 複製到 %s 嗎?',[pszSrcFile,pszDestFile]);
  FO_DELETE:  sOp:=format('你確定要將 %s 刪除嗎?',[pszSrcFile]);
  FO_MOVE:  sOp:=format('你確定要將 %s 轉移到 %s 嗎?',[pszSrcFile,pszDestFile]);
  FO_RENAME:  sOp:=format('你確定要將 %s 重新命名為 %s 嗎?',[pszSrcFile,pszDestFile]);
  else
  sOp:=format('無法識別的操作程式碼 %d',[wFlags]);
  end;
  // 提示,讓使用者決定是否執行操作
  Result := MessageBox(Wnd,  PChar(sOp),
  '檔案掛鉤演示', MB_YESNOCANCEL);
end;

{ TCopyHookFactory }

function TCopyHookFactory.GetProgID: string;
begin
  Result := '';
end;

procedure TCopyHookFactory.UpdateRegistry(Register: Boolean);
var
  ClsID: string;
begin
  ClsID := GUIDToString(ClassID);
  inherited UpdateRegistry(Register);
  ApproveShellExtension(Register, ClsID);
  if Register then
  clsid 加入到登錄檔的CopyHookHandlers中
  CreateRegKey('directoryshellexCopyHookHandlers' + ClassName, '',
  ClsID)
  else
  DeleteRegKey('directoryshellexCopyHookHandlers' + ClassName);
end;

procedure TCopyHookFactory.ApproveShellExtension(Register: Boolean;
  const ClsID: string);
const
  SApproveKey = 'SOFTWAREWindowsCurrentVersionShell ExtensionsApproved';
begin
  with TRegistry.Create do
  try
  RootKey := HKEY_LOCAL_MACHINE;
  if not OpenKey(SApproveKey, True) then Exit;
  if Register then WriteString(ClsID, Description)
  else DeleteValue(ClsID);
  finally
  Free;
  end;
end;

const
  CLSID_CopyHook: TGUID = '{66CD5F60-A044-11D0-A9BF-00A024E3867F}';
  LIBID_CopyHook: TGUID = '{D2F531A0-0861-11D2-AE5C-74640BC10000}';

initialization
  TCopyHookFactory.Create(ComServer, TCopyHook, CLSID_CopyHook,
  'CR_CopyHook', '檔案操作掛鉤演示',ciMultiInstance, tmApartment);
end.
將檔案儲存為CopyMain.Pas檔案,然後編譯程式為CopyHook.Dll檔案,然後註冊CopyHook.Dll檔案,你可以使用Windows提供的RegSvr32.exe來註冊,註冊的方法是在Dos視窗中進入Windows的System子目錄,然後在其中輸入Regsvr32 x:xxxxxxcopyhook.dll ,其中x:xxxxxx是編譯的CopyHook.dll所在的全路徑名。也可以在Run選單中選擇Register Server來註冊。
當檔案註冊成功之後,在Windows的Explore中任意改變一個資料夾的名字或者移動一個目錄,就會有一個提示框彈出,提示使用者是否確定執行操作。如圖所示:

 

 按“是”將執行資料夾操作,按“否”或者“取消”將取消相應的資料夾操作。
 上面介紹的只是Delphi實現Windows外殼擴充套件的一種,參照上面的程式和Delphi關於Windows的COM元件模型的程式設計,就可以編寫出十分專業化的Windows外殼擴充套件程式。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988115/,如需轉載,請註明出處,否則將追究法律責任。

相關文章