现在我吧代码贴上来吧: DiscMonitor:<br>// ==================== DISC DRIVE MONITOR =====================================<br>//<br>// Class and Component to encapsulate the FindXXXXChangeNotification API calls<br>//<br>// The FindXXXXChangeNotification API calls set up a disc contents change<br>// notification handle. You can set a filter to control which change types<br>// are notified, the directory which is monitored and set whether subdirectories<br>// from the monitored directory are monitored as well.<br>//<br>//------------------------------------------------------------------------------<br>// This file contains a class derived from TThread which undertakes the disc<br>// monitoring and a simple component which encapsulates the thread to make<br>// a non-visual VCL component. This component works at design time, monitoring<br>// and notifying changes live if required.<br>//<br>// Version 1.00 - Grahame Marsh 14 January 1997<br>// Version 1.01 - Grahame Marsh 30 December 1997<br>// Bug fix - really a Win 95 bug but only surfaces in D3, not D2<br>// - see notes in execute method<br>// Version 1.02 - Grahame Marsh 30 January 1998<br>// - adapted to work with version 2.30 TBrowseDirectoryDlg<br>//<br>// Freeware - you get it for free, I take nothing, I make no promises!<br>//<br>// Please feel free to contact me: grahame.s.marsh@courtaulds.com<br><br>unit DiscMon;<br><br>interface<br><br>uses<br> Windows, Messages, SysUtils, Classes, Graphics, Controls,<br> Forms, Dialogs, ShlObj{, BrowseDr, DsgnIntf ie02};<br><br>//=== DISC MONITORING THREAD ===================================================<br>// This thread will monitor a given directory and subdirectories (if required)<br>// for defined filtered changes. When a change occurs the OnChange event will<br>// be fired, if an invalid condition is found (eg non-existent path) then<br>// the OnInvalid event is fired. Each event is called via the Sychronize method<br>// and so are VCL thread safe.<br>//<br>// The thread is created suspended, so after setting the required properties<br>// you must call the Resume method.<br><br><br>type<br> TDiscMonitorThread = class(TThread)<br> private<br> FOnChange : TNotifyEvent;<br> FOnInvalid : TNotifyEvent;<br> FDirectory : string;<br> FFilters : integer;<br> FDestroyEvent,<br> FChangeEvent : THandle;<br> FSubTree : boolean;<br> fChangeDelay : Integer; {ie01}<br> procedure InformChange;<br> procedure InformInvalid;<br> procedure SetDirectory (const Value : string);<br> procedure SetFilters (Value : integer);<br> procedure SetSubTree (Value : boolean);<br> protected<br> procedure Execute; override;<br> procedure Update;<br> public<br> constructor Create;<br> destructor Destroy; override;<br>// The directory to monitor<br> property Directory : string read FDirectory write SetDirectory;<br>// Filter condition, may be any of the FILE_NOTIFY_CHANGE_XXXXXXX constants<br>// ORed together. Zero is invalid.<br> property Filters : integer read FFilters write SetFilters;<br>// Event called when change noted in directory<br> property OnChange : TNotifyEvent read FOnChange write FOnChange;<br>// Event called for invalid parameters<br> property OnInvalid : TNotifyEvent read FOnInvalid write FOnInvalid;<br>// Include subdirectories below specified directory.<br> property SubTree : boolean read FSubTree write SetSubTree;<br>// specify, how long the thread should wait, before the event OnChange is fired:<br> Property ChangeDelay : Integer Read fChangeDelay Write fChangeDelay {ie01}<br> Default 500; {ie01}<br> end;<br><br>//===================== DISC MONITORING COMPONENT ==============================<br><br>// specify directory string as type string so we can have our own property editor<br> TDiscMonitorDirStr = type string;<br><br>// enumerated type for filter conditions (not directly usable in thread class)<br>// see the SetFilters procedure for the translation of these filter conditions<br>// into FILE_NOTIFY_CHANGE_XXXXXX constants.<br> TMonitorFilter = (moFilename, moDirName, moAttributes, moSize,<br> moLastWrite, moSecurity);<br>// set of filter conditions<br> TMonitorFilters = set of TMonitorFilter;<br><br> TDiscMonitor = class(TComponent)<br> private<br> FActive : boolean;<br> FMonitor : TDiscMonitorThread;<br> FFilters : TMonitorFilters;<br> FOnChange : TNotifyEvent;<br> FOnInvalid : TNotifyEvent;<br> FShowMsg : boolean;<br> function GetDirectory : TDiscMonitorDirStr;<br> function GetSubTree : boolean;<br> procedure SetActive (Value : boolean);<br> procedure SetDirectory (Value : TDiscMonitorDirStr);<br> procedure SetFilters (Value : TMonitorFilters);<br> procedure SetSubTree (Value : boolean);<br> Function GetChangeDelay : Integer; {ie01}<br> Procedure SetChangeDelay(Value : Integer); {ie01}<br> protected<br> procedure Change (Sender : TObject);<br> procedure Invalid (Sender : TObject);<br> public<br> constructor Create (AOwner : TComponent); Override;<br> destructor Destroy; override;<br>// stop the monitoring thread running<br> procedure Close;<br>// start the monitoring thread running<br> procedure Open;<br>// read-only property to access the thread directly<br> property Thread : TDiscMonitorThread read FMonitor;<br> published<br>// the directory to monitor<br> property Directory : TDiscMonitorDirStr read GetDirectory write SetDirectory;<br>// control the appearance of information messages at design time (only)<br> property ShowDesignMsg : boolean read FShowMsg write FShowMsg default false;<br>// event called when a change is notified<br> property OnChange : TNotifyEvent read FOnChange write FOnChange;<br>// event called if an invalid condition is found<br> property OnInvalid : TNotifyEvent read FOnInvalid write FOnInvalid;<br>// notification filter conditions<br> property Filters : TMonitorFilters read FFilters write SetFilters default [moFilename];<br>// include subdirectories below the specified directory<br> property SubTree : boolean read GetSubTree write SetSubTree default true;<br>// specify if the monitoring thread is active<br> property Active : boolean read FActive write SetActive default false;<br>// specify, how long the thread should wait, before the event OnChange is fired:<br> Property ChangeDelay : Integer Read GetChangeDelay Write SetChangeDelay {ie01}<br> Default 500; {ie01}<br> end;<br><br>procedure Register;<br><br>implementation<br><br>//=== MONITOR THREAD ===========================================================<br><br>// Create the thread suspended. Create two events, each are created using<br>// standard security, in the non-signalled state, with auto-reset and without<br>// names. The FDestroyEvent will be used to signal the thread that it is to close<br>// down. The FChangeEvent will be used to signal the thread when the monitoring<br>// conditions (directory, filters or sub-directory search) have changed.<br>// OnTerminate is left as false, so the user must Free the thread.<br><br>constructor TDiscMonitorThread.Create;<br>begin<br> inherited Create (true);<br> FDestroyEvent := CreateEvent (nil, true, false, NIL);<br> FChangeEvent := CreateEvent (nil, false, false, NIL);<br>end;<br><br>// close OnXXXXX links, signal the thread that it is to close down<br>destructor TDiscMonitorThread.Destroy;<br>begin<br> FOnChange := nil;<br> FOnInvalid := nil;<br> SetEvent (FDestroyEvent);<br> FDirectory := '';<br> inherited Destroy<br>end;<br><br>// called by the Execute procedure via Synchronize. So this is VCL thread safe<br>procedure TDiscMonitorThread.InformChange;<br>begin<br> if Assigned (FOnChange) then<br> FOnChange (Self)<br>end;<br><br>// called by the Execute procedure via Synchronize. So this is VCL thread safe<br>procedure TDiscMonitorThread.InformInvalid;<br>begin<br> if Assigned (FOnInvalid) then<br> FOnInvalid (Self)<br>end;<br><br>// Change the current directory<br>procedure TDiscMonitorThread.SetDirectory (const Value : string);<br>begin<br> if Value <> FDirectory then<br> begin<br> FDirectory := Value;<br> Update<br> end<br>end;<br><br>// Change the current filters<br>procedure TDiscMonitorThread.SetFilters (Value : integer);<br>begin<br> if Value <> FFilters then<br> begin<br> FFilters := Value;<br> Update<br> end<br>end;<br><br>// Change the current sub-tree condition<br>procedure TDiscMonitorThread.SetSubTree (Value : boolean);<br>begin<br> if Value <> FSubTree then<br> begin<br> FSubtree := Value;<br> Update<br> end<br>end;<br><br><br>Function TDiscMonitor.GetChangeDelay : Integer; {ie01}<br>begin<br> Result := FMonitor.ChangeDelay;<br>end;<br><br><br>Procedure TDiscMonitor.SetChangeDelay(Value : Integer); {ie01}<br>begin<br> FMonitor.ChangeDelay := Value;<br>end;<br><br><br>// On any of the above three changes, if the thread is running then<br>// signal it that a change has occurred.<br>procedure TDiscMonitorThread.Update;<br>begin<br> if not Suspended then<br> SetEvent (FChangeEvent)<br>end;<br><br>// The EXECUTE procedure<br>// -------<br>// Execute needs to:<br>// 1. Call FindFirstChangeNotification and use the Handle in a WaitFor...<br>// to wait until the thread become signalled that a notification has occurred.<br>// The OnChange event is called and then the FindNextChangeNotification is<br>// the called and Execute loops back to the WaitFor<br>// 2. If an invalid handle is obtained from the above call, the the OnInvalid<br>// event is called and then Execute waits until valid conditions are set.<br>// 3. If a ChangeEvent is signalled then FindCloseChangeNotification is called,<br>// followed by a new FindFirstChangeNotification to use the altered<br>// conditions.<br>// 4. If a DestroyEvent is signalled then FindCloseChangeNotification is<br>// called and the two events are closed and the thread terminates.<br>//<br>// In practice WaitForMultipleObjects is used to wait for any of the conditions<br>// to be signalled, and the returned value used to determine which event occurred.<br><br>procedure TDiscMonitorThread.Execute;<br>// There appears to be a bug in win 95 where the bWatchSubTree parameter<br>// of FindFirstChangeNotification which is a BOOL only accepts values of<br>// 0 and 1 as valid, rather than 0 and any non-0 value as it should. In D2<br>// BOOL was defined as 0..1 so the code worked, in D3 it is 0..-1 so<br>// fails. The result is FindF... produces and error message. This fix (bodge) is<br>// needed to produce a 0,1 bool pair, rather that 0,-1 as declared in D3<br>const<br> R : array [false..true] of BOOL = (BOOL (0), BOOL (1));<br>var<br> A : array [0..2] of THandle; // used to give the handles to WaitFor...<br> B : boolean; // set to true when the thread is to terminate<br>begin<br> B := false;<br> A [0] := FDestroyEvent; // put DestroyEvent handle in slot 0<br> A [1] := FChangeEvent; // put ChangeEvent handle in slot 1<br>// make the first call to the change notification system and put the returned<br>// handle in slot 2.<br> A [2] := FindFirstChangeNotification (PChar(FDirectory), R[fSubTree], FFilters);<br> repeat<br><br>// if the change notification handle is invalid then:<br> if A [2] = INVALID_HANDLE_VALUE then<br> begin<br> // call the OnInvalid event<br> Synchronize (InformInvalid);<br> // wait until either DestroyEvent or the ChangeEvents are signalled<br> case WaitForMultipleObjects (2, PWOHandleArray (@A), false, INFINITE) - WAIT_OBJECT_0 of<br> // DestroyEvent - close down by setting B to true<br> 0 : B := true;<br> // try new conditions and loop back to the invalid handle test<br> 1 : A [2] := FindFirstChangeNotification (PChar(FDirectory), R[fSubTree], FFilters)<br> end<br> end else<br>// handle is valid so wait for any of the change notification, destroy or<br>// change events to be signalled<br> case WaitForMultipleObjects (3, PWOHandleArray (@A), false, INFINITE) - WAIT_OBJECT_0 of<br> 0 : begin<br> // DestroyEvent signalled so use FindClose... and close down by setting B to true<br> FindCloseChangeNotification (A [2]);<br> B := true<br> end;<br> 1 : begin<br> // ChangeEvent signalled so close old conditions by FindClose... and start<br> // off new conditions. Loop back to invalid test in case new conditions are<br> // invalid<br> FindCloseChangeNotification (A [2]);<br> A [2] := FindFirstChangeNotification (PChar(FDirectory), R[fSubTree], FFilters)<br> end;<br> 2 : begin<br> // Notification signalled, so fire the OnChange event and then FindNext..<br> // loop back to re-WaitFor... the thread<br> Sleep(fChangeDelay); {ie01 ins}<br> Synchronize (InformChange);<br> FindNextChangeNotification (A [2])<br> end;<br> end<br> until B Or Self.Terminated;<br><br>// closing down so chuck the two events<br> CloseHandle (FChangeEvent);<br> CloseHandle (FDestroyEvent)<br>end;<br><br>//=== MONITOR COMPONENT ========================================================<br><br>// This component encapsulates the above thread. It has properties for<br>// directory, sub-directory conditions, filters, whether information messages<br>// should be given at design time and if the thread is active.<br>constructor TDiscMonitor.Create (AOwner : TComponent);<br>begin<br> inherited Create (AOwner);<br> FMonitor := TDiscMonitorThread.Create; // create a monitor thread<br> FMonitor.ChangeDelay := 500; {ie01}<br> FMonitor.OnChange := Change; // hook into its event handlers<br> FMonitor.OnInvalid := Invalid;<br> Filters := [moFilename]; // default filters to moFilename<br> SubTree := true // default sub-tree search to on<br>end;<br><br>destructor TDiscMonitor.Destroy;<br>begin<br> FMonitor.Free; // chuck the thread<br> inherited Destroy<br>end;<br><br>// Change notification from the thread has occurred. Call the component's event<br>// handler and then, if in design mode, and if desired, put up a simple<br>// notification message<br>procedure TDiscMonitor.Change;<br>begin<br> if Assigned (FOnChange) then<br> FOnChange (Self)<br> else<br> if (csDesigning in ComponentState) and FShowMsg then<br> ShowMessage ('Change signalled')<br>end;<br><br>// Invalid notification from the thread has occurred. Call the component's event<br>// handler and then, if in design mode, and if desired, put up a simple<br>// notification message<br>procedure TDiscMonitor.Invalid;<br>begin<br> if Assigned (FOnInvalid) then<br> FOnInvalid (Self)<br> else<br> if (csDesigning in ComponentState) and FShowMsg then<br> ShowMessage ('Invalid parameter signalled')<br>end;<br><br>// Stop the monitor running<br>procedure TDiscMonitor.Close;<br>begin<br> Active := false<br>end;<br><br>// Run the monitor<br>procedure TDiscMonitor.Open;<br>begin<br> Active := true<br>end;<br><br>// Control the thread by using it's resume and suspend methods<br>procedure TDiscMonitor.SetActive (Value : boolean);<br>begin<br> if Value <> FActive then<br> begin<br> FActive := Value;<br> if Active then<br> begin<br> FMonitor.Resume;<br> FMonitor.Update<br> end else<br> FMonitor.Suspend<br> end<br>end;<br><br>// get the current directory from the thread<br>function TDiscMonitor.GetDirectory : TDiscMonitorDirStr;<br>begin<br> Result := FMonitor.Directory<br>end;<br><br>// get the current sub-tree status from the thread<br>function TDiscMonitor.GetSubTree : boolean;<br>begin<br> Result := FMonitor.SubTree<br>end;<br><br>// set the directory to monitor<br>procedure TDiscMonitor.SetDirectory (Value : TDiscMonitorDirStr);<br>begin<br> FMonitor.Directory := Value<br>end;<br><br>// Change the filter conditions. The thread uses the raw windows constants<br>// (FILE_NOTIFY_CHANGE_XXXX) but the components uses a set of enumurated type.<br>// It is therefore necessary to translate from the component format into<br>// an integer value for the thread.<br>procedure TDiscMonitor.SetFilters (Value : TMonitorFilters);<br>const<br> XlatFileNotify : array [moFilename..moSecurity] of integer =<br> (FILE_NOTIFY_CHANGE_FILE_NAME, FILE_NOTIFY_CHANGE_DIR_NAME,<br> FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_NOTIFY_CHANGE_SIZE,<br> FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_NOTIFY_CHANGE_SECURITY);<br>var<br> L : TMonitorFilter;<br> I : integer;<br>begin<br> if Value <> FFilters then<br> if Value = [] then<br> ShowMessage ('Some filter condition must be set.')<br> else begin<br> FFilters := Value;<br> I := 0;<br> for L := moFilename to moSecurity do<br> if L in Value then<br> I := I or XlatFileNotify [L];<br> FMonitor.Filters := I;<br> end<br>end;<br><br>// set the sub-tree status in the thread<br>procedure TDiscMonitor.SetSubTree (Value : boolean);<br>begin<br> FMonitor.SubTree := Value<br>end;<br><br>procedure Register;<br>begin<br> RegisterComponents ('FileSys', [TDiscMonitor]);<br> {RegisterPropertyEditor (TypeInfo (TDiscMonitorDirStr), nil, '', TDiscMonitorDirStrProperty);}<br>end;<br><br>end.<br>另外如果是在NT下面,调用得函数是CreateIOCompletionPort<br>而不是CreateCompletionPort,上次说错了.
<br>用ReadDirectoryChangesW与上面得方法相似.<br>这是一个外国人的代码.