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

利用Windows外殼擴展保護文件夾

編輯:Delphi

利用Windows外殼擴展保護文件夾
在Win32操作系統(包括Win9X、Windows NT、Windows 2000)不但有方便的圖形用戶(GUI)界面,微軟還為windows用戶界面保留了強大的可擴充性。其中對於Windows界面的操作環境(這裡稱為外殼Shell),微軟提供了一種稱為外殼擴展(Shell Extensions)的功能來實現文件系統操作的可編程性。如果你的機器中安裝了Word 7.0以上的版本,當你鼠標右鍵單擊一個DOC文件,在彈出菜單中選“屬性”項,在屬性頁中不僅顯示顯示文件的大小、建立日期等信息,同時還增加了Doc文檔的摘要、統計等信息;又例如安裝了winZip 6.0以上版本後,當選中一個或多個文件或文件夾後在單擊鼠標右鍵,在彈出的右鍵菜單中就增加了“Add To Zip”等一個zip文件壓縮選項。上面的這些功能都是通過Windows外殼擴展來實現的。
Windows外殼擴展是這樣實現的。首先要編寫外殼擴展程序,一個外殼擴展程序是基於COM(Component Object Model)組件模型的。外殼是通過接口(Interface)來訪問對象的。外殼擴展被設計成32位的進程中服務器程序,並且都是以動態鏈接庫的形式為操作系統提供服務的。
寫好外殼擴展程序後,必須將它們注冊才能生效。所有的外殼擴展都必須在Windows注冊表的HKEY_CLASSES_ROOTCLSID鍵之下進行注冊。在該鍵下面可以找到許多名字像{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對象的過程,由於Delphi4.0以上的版本支持Windows外殼擴展和COM組件模型,所以可以利用Delphi來編寫外殼擴展程序。
利用Delphi編寫Copy-hook handle需要實現ICopyHook接口。ICopyHook是一個十分簡單的接口,要實現的只有CopyCallBack方法。ICopyHook的CopyCallBack方法的定義如下:
UINT CopyCallback(
    HWND hwnd, file://Handle of the parent window for displaying UI objects
    UINT wFunc, file://Operation to perform.
    UINT wFlags, file://Flags that control the operation
    LPCSTR pszSrcFile, file://Pointer to the source file
    DWORD dwSrcAttribs, file://Source file attributes
    LPCSTR pszDestFile, file://Pointer to the destination file
    DWORD dwDestAttribs file://Destination 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; override;
    procedure ApproveShellExtension(Register: Boolean; const ClsID: string);
      virtual;
  public
    procedure UpdateRegistry(Register: Boolean); override;
  end;

implementation

uses ComServ, SysUtils, Registry;

{ TCopyHook }

file://當Windows外殼程序執行文件夾或者打印機端口操作時,CopyCallBack
file://方法就會被調用。
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
    file://將clsid 加入到注冊表的CopyHookHandlers中
    CreateRegKey(directoryshellexCopyHookHandlers + ClassName, ,
      ClsID)
  else
    DeleteRegKey(directoryshellexCopyHookHandlers + ClassName);
end;

procedure TCopyHookFactory.ApproveShellExtension(Register: Boolean;
  const ClsID: string);
const
  SAp

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