線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1591
推到 Plurk!
推到 Facebook!

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

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-08-16 16:23:13 IP:61.218.xxx.xxx 未訂閱

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

wwwa.applevb.com 在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外殼)操作,各位 讀者可以參考相應的參考資料。 聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]--- 發表人 - axsoft 於 2002/08/16 16:25:46
系統時間:2024-04-25 14:47:51
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!