程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 利用未公開函數實現Shell操作監視

利用未公開函數實現Shell操作監視

編輯:Delphi
  在Windows下有一個未公開函數SHChangeNotifyRegister可以吧你的窗口添加到系統的系統消息監視鏈中,該函數在Delphi
  中的定義如下:
  Function SHChangeNotifyRegister(hWnd,uFlags,dwEventID,uMSG,cItems:LongWord;
           lPPS:PIDLSTRUCT):integer;stdcall;external 'Shell32.dll' index 2;
  其中參數hWnd定義了監視系統操作的窗口得句柄,參數uFlags dwEventID定義監視操作參數,參數uMsg定義操作消息,參數cItems
  定義附加參數,參數lPPS指定一個PIDLSTRUCT結構,該結構指定監視的目錄。
      當函數調用成功之後,函數會返回一個監視操作句柄,同時系統就會將hWnd指定的窗口加入到操作監視鏈中,當有文件操作發生
  時,系統會向hWnd發送uMsg指定的消息,我們只要在程序中加入該消息的處理函數就可以實現對系統操作的監視了。
  如果要退出程序監視,就要調用另外一個未公開得函數SHChangeNotifyDeregister來取消程序監視。
      下面是使用Delphi編寫的具體程序實現范例,首先建立一個新的工程文件,然後在Form1中加入一個Button控件和一個Memo控件,
  程序的代碼如下:

  unit Unit1;

  interface

  uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    StdCtrls,shlobj,Activex;

  const
    SHCNE_RENAMEITEM = $1;
    SHCNE_CREATE = $2;
    SHCNE_DELETE = $4;
    SHCNE_MKDIR = $8;
    SHCNE_RMDIR = $10;
    SHCNE_MEDIAINSERTED = $20;
    SHCNE_MEDIAREMOVED = $40;
    SHCNE_DRIVEREMOVED = $80;
    SHCNE_DRIVEADD = $100;
    SHCNE_NETSHARE = $200;
    SHCNE_NETUNSHARE = $400;
    SHCNE_ATTRIBUTES = $800;
    SHCNE_UPDATEDIR = $1000;
    SHCNE_UPDATEITEM = $2000;
    SHCNE_SERVERDISCONNECT = $4000;
    SHCNE_UPDATEIMAGE = $8000;
    SHCNE_DRIVEADDGUI = $10000;
    SHCNE_RENAMEFOLDER = $20000;
    SHCNE_FREESPACE = $40000;
    SHCNE_ASSOCCHANGED = $8000000;
    SHCNE_DISKEVENTS = $2381F;
    SHCNE_GLOBALEVENTS = $C0581E0;
    SHCNE_ALLEVENTS = $7FFFFFFF;
    SHCNE_INTERRUPT = $80000000;

    SHCNF_IDLIST = 0;               //  LPITEMIDLIST
    SHCNF_PATHA = $1;               // path name
    SHCNF_PRINTERA = $2;            // printer frIEndly name
    SHCNF_DWORD = $3;               // DWord
    SHCNF_PATHW = $5;               // path name
    SHCNF_PRINTERW = $6;            // printer frIEndly name
    SHCNF_TYPE = $FF;

    SHCNF_FLUSH = $1000;

    SHCNF_FLUSHNOWAIT = $2000;
    SHCNF_PATH = SHCNF_PATHW;
    SHCNF_PRINTER = SHCNF_PRINTERW;

    WM_SHNOTIFY = $401;
    NOERROR = 0;

  type
    TForm1 = class(TForm)
      Button1: TButton;
      Memo1: TMemo;
      procedure FormClose(Sender: TObject; var Action: TCloseAction);
      procedure Button1Click(Sender: TObject);
      procedure FormCreate(Sender: TObject);
    private
      { Private declarations }
      procedure WMShellReg(var Message:TMessage);message WM_SHNOTIFY;
    public
      { Public declarations }
    end;

  type PSHNOTIFYSTRUCT=^SHNOTIFYSTRUCT;
    SHNOTIFYSTRUCT = record
      dwItem1 : PItemIDList;
      dwItem2 : PItemIDList;
    end;

  Type PSHFileInfoByte=^SHFileInfoByte;
    _SHFileInfoByte = record
      hIcon :Integer;
      iIcon :Integer;
      dwAttributes : Integer;
      szDisplayName : array [0..259] of char;
      szTypeName : array [0..79] of char;
    end;
    SHFileInfoByte=_SHFileInfoByte;

  Type PIDLSTRUCT = ^IDLSTRUCT;
    _IDLSTRUCT = record
      pidl : PItemIDList;
      bWatchSubFolders : Integer;
    end;
    IDLSTRUCT =_IDLSTRUCT;

  
  function SHNotify_Register(hWnd : Integer) : Bool;
  function SHNotify_UnRegister:Bool;
  function SHEventName(strPath1,strPath2:string;lParam:Integer):string;

  Function SHChangeNotifyDeregister(hNotify:integer):integer;stdcall;
           external 'Shell32.dll' index 4;
  Function SHChangeNotifyRegister(hWnd,uFlags,dwEventID,uMSG,cItems:LongWord;
           lPPS:PIDLSTRUCT):integer;stdcall;external 'Shell32.dll' index 2;
  Function SHGetFileInfoPidl(pidl : PItemIDList;
           dwFileAttributes : Integer;
           psfib : PSHFILEINFOBYTE;
           cbFileInfo : Integer;
           uFlags : Integer):Integer;stdcall;
           external 'Shell32.dll' name 'SHGetFileInfoA';

  var
    Form1: TForm1;
    m_hSHNotify:Integer;
    m_pidlDesktop : PItemIDList;

  implementation

  {$R *.DFM}

  function SHEventName(strPath1,strPath2:string;lParam:Integer):string;
  var
    sEvent:String;
  begin
    case lParam of        file://根據參數設置提示消息
      SHCNE_RENAMEITEM: sEvent := '重命名文件'+strPath1+'為'+strpath2;
      SHCNE_CREATE: sEvent := '建立文件 文件名:'+strPath1;
      SHCNE_DELETE: sEvent := '刪除文件 文件名:'+strPath1;
      SHCNE_MKDIR: sEvent := '新建目錄 目錄名:'+strPath1;
      SHCNE_RMDIR: sEvent := '刪除目錄 目錄名:'+strPath1;
      SHCNE_MEDIAINSERTED: sEvent := strPath1+'中插入可移動存儲介質';
      SHCNE_MEDIAREMOVED: sEvent := strPath1+'中移去可移動存儲介質'+strPath1+' '+strpath2;
      SHCNE_DRIVEREMOVED: sEvent := '移去驅動器'+strPath1;
      SHCNE_DRIVEADD: sEvent := '添加驅動器'+strPath1;
      SHCNE_NETSHARE: sEvent := '改變目錄'+strPath1+'的共享屬性';

      SHCNE_ATTRIBUTES: sEvent := '改變文件目錄屬性 文件名'+strPath1;
      SHCNE_UPDATEDIR: sEvent := '更新目錄'+strPath1;
      SHCNE_UPDATEITEM: sEvent := '更新文件 文件名:'+strPath1;
      SHCNE_SERVERDISCONNECT: sEvent := '斷開與服務器的連接'+strPath1+' '+strpath2;
      SHCNE_UPDATEIMAGE: sEvent := 'SHCNE_UPDATEIMAGE';
      SHCNE_DRIVEADDGUI: sEvent := 'SHCNE_DRIVEADDGUI';
      SHCNE_RENAMEFOLDER: sEvent := '重命名文件夾'+strPath1+'為'+strpath2;
      SHCNE_FREESPACE: sEvent := '磁盤空間大小改變';
      SHCNE_ASSOCCHANGED: sEvent := '改變文件關聯';
    else
      sEvent:='未知操作'+IntToStr(lParam);
    end;
    Result:=sEvent;
  end;

  function SHNotify_Register(hWnd : Integer) : Bool;
  var
    ps:PIDLSTRUCT;
  begin
    {$R-}
    Result:=False;
    If m_hSHNotify = 0 then begin
      file://獲取桌面文件夾的Pidl
      if SHGetSpecialFolderLocation(0, CSIDL_DESKTOP,
          m_pidlDesktop)<> NOERROR then
          Form1.close;
      if Boolean(m_pidlDesktop) then begin
        ps.bWatchSubFolders := 1;
        ps.pidl := m_pidlDesktop;

        // 利用SHChangeNotifyRegister函數注冊系統消息處理
        m_hSHNotify := SHChangeNotifyRegister(hWnd, (SHCNF_TYPE Or SHCNF_IDLIST),
                                            (SHCNE_ALLEVENTS Or SHCNE_INTERRUPT),
                                            WM_SHNOTIFY, 1, ps);
        Result := Boolean(m_hSHNotify);
      end
      Else
        // 如果出現錯誤就使用 CoTaskMemFree函數來釋放句柄
        CoTaskMemFree(m_pidlDesktop);
    End;
    {$R+}
  end;

  function SHNotify_UnRegister:Bool;
  begin
    Result:=False;
    If Boolean(m_hSHNotify) Then
      file://取消系統消息監視,同時釋放桌面的Pidl
      If Boolean(SHChangeNotifyDeregister(m_hSHNotify)) Then begin
        {$R-}
        m_hSHNotify := 0;
        CoTaskMemFree(m_pidlDesktop);
        Result := True;
        {$R-}
      End;
  end;

  procedure TForm1.WMShellReg(var Message:TMessage);      file://系統消息處理函數
  var
    strPath1,strPath2:String;
    charPath:array[0..259]of char;
    pidlItem:PSHNOTIFYSTRUCT;
  begin
    pidlItem:=PSHNOTIFYSTRUCT(Message.wParam);
    file://獲得系統消息相關得路徑
    SHGetPathFromIDList(pidlItem.dwItem1,charPath);
    strPath1:=charPath;
    SHGetPathFromIDList(pidlItem.dwItem2,charPath);
    strPath2:=charPath;

    Memo1.Lines.Add(SHEvEntName(strPath1,strPath2,Message.lParam)+chr(13)+chr(10));
  end;

  procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
  begin
    file://在程序退出的同時刪除監視
    if Boolean(m_pidlDesktop) then
      SHNotify_Unregister;
  end;

  procedure TForm1.Button1Click(Sender: TObject); file://Button1的Click消息
  begin
    m_hSHNotify:=0;
    if SHNotify_Register(Form1.Handle) then begin file://注冊Shell監視
      ShowMessage('Shell監視程序成功注冊');
      Button1.Enabled := False;
    end
    else
      ShowMessage('Shell監視程序注冊失敗');
  end;

  procedure TForm1.FormCreate(Sender: TObject);
  begin
    Button1.Caption := '打開監視';
  end;

  end.

      運行程序,點擊“打開監視”按鈕,如果出現一個顯示“Shell監視程序成功注冊”的對話框,說明Form1已經加入到系統操作監視鏈中了,
  你可以試著在資源管理器中建立、刪除文件夾,移動文件等操作,你可以發現這些操作都被紀錄下來並顯示在文本框中。
      在上面的程序中多次使用到了一個PItemIDList的結構,這個數據結構指定Windows下得一個“項目”,在Windows下資源實現統一管理
  一個“項目”可以是一個文件或者一個文件夾,也可以是一個打印機等資源。另外一些API函數也涉及到了Shell(Windows外殼)操作,各位
  讀者可以參考相應的參考資料。

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