Better monitoring of change notification handles

Hello
   I am currently monitoring changes using change notification handles (FindFirstChangeNotification) in a custom control. It works well, but teh control requires focus to update the view. I would like it to be autonomous, in that it will respond privately and immediately to notified handles, perhaps by hooking a windows-issued message (if any) or by having a TEvent object initiate the update (I would prefer this). I currently check the handles manually in some general events (for-loop checking a THandle array with WaitforSingleObject...). I would also like to avoid instantiating a (an addtional!) thread or using a timer (same thing). Is this possible?

Any suggestions?

Regards,
Edo
LVL 1
Edo082297Asked:
Who is Participating?
 
interConnect With a Mentor Commented:
Thanks friend,
just call if you need cooperation
Regards, Igor
0
 
MatveyCommented:
Maybe you search for a message like WM_DeviceChange? A message that will notify you when new files are written and deleted? (I think it's not exactly THE message, I just can't recall the exact one...)
0
 
interCommented:
Hi Edo,
The change notification is almost instantly triger a specified object. So, your focusing problem is due to the component design. In my opinion(and also programmed an object for it previously) using a seperate thread object which watches for multiple events are what you need. Here what I have programmed before:-it is a code fragment from my unit-

//*********CODE STARTS
// This one can poll a directory for changes
type
  TDirNotify = class(TThread)
  protected
    FDir : string;   //directory to watch
    FWObj: THandle;  //event handle given by OS
    FOnChange : TNotifyEvent;
    procedure SetDir(D : String);
    procedure Execute;override;
  public
    constructor Create(ADir : string);
    destructor Destroy;override;
    property Directory : string read FDir write SetDir;
    property OnChange : TNotifyEvent read FOnChange write FOnChange;
  end;

implementation


{$R *.DFM}

// ****************************************************************
// TDirNotify
// ****************************************************************

procedure TDirNotify.SetDir(D : String);
begin
  if D <> FDir then
  begin
    FDir := D;
    if FWObj <> 0 then
       FindCloseChangeNotification(FWObj);
    FWObj := FindFirstChangeNotification(PChar(FDir), false,
                                             FILE_NOTIFY_CHANGE_FILE_NAME //or
//                                             FILE_NOTIFY_CHANGE_DIR_NAME or
//                                             FILE_NOTIFY_CHANGE_ATTRIBUTES or
//                                             FILE_NOTIFY_CHANGE_SIZE or
//                                             FILE_NOTIFY_CHANGE_LAST_WRITE or
//                                             FILE_NOTIFY_CHANGE_SECURITY
                                               );
    if FWObj = INVALID_HANDLE_VALUE then
       raise Exception.Create('TDirNotify.SetDir : Can not hook a directory notification filter');
  end;
end;

procedure TDirNotify.Execute;
begin
  while not Terminated do
  begin
    if WaitForSingleObject(FWObj, 1000) = WAIT_OBJECT_0 then
    begin
      try //catch exceptions due to the user
        if Assigned(FOnChange) then FOnChange(Self);
      except
      end;
      FindNextChangeNotification(FWObj);
    end;
    Sleep(10);
  end;
end;

constructor TDirNotify.Create(ADir : string);
begin
  inherited Create(False);
  FWObj:= 0;
  Directory := ADir;
  FreeOnTerminate := true;
end;

destructor TDirNotify.Destroy;
begin
  if FWObj <> 0 then
     FindCloseChangeNotification(FWObj);
  inherited Destroy;
end;
//*********CODE ENDS

You can change the object you watch at create, above i only check for rename operations. It is not a component so you have to create an instance of it by yourself.
First create it and assign OnChange event to it.
Regards, Igor
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
Edo082297Author Commented:
Hi Igor

I have no problem with what you are suggesting, but Delphi documentation recommends no more than 16 threads in the same session. I currently add a notification handle whenever the user is in a particular directory, so I could potentially end up with a lot of threads. Isn't this a problem? I would almost prefer to use a timer and check all the handles in one shot, rather than instantiate a separate thread for each one. But I don't like the timer solution because it lacks sophistication(!). Then again, perhaps it is the best solution. What do you think?

Regards,
Edo


0
 
interCommented:
Hi
we can solve it with single thread and by using waitformultipleobject instead for wait for single object. Then we change the type of OnChange as follows
  TOnChangeEvent = procedure (const DirName);
By this way, when we detect change notification we call the onchange with the coresponding directory name.
This should pose additional coding such adding AddNotification(dirname:string) and holding all the dirs and coresponding notification event handles in that class -may be in stringlist- (By now I have no time to implement this but may be tomorrow I can...or any other friend-may be you- can do it without much effort)
Regards, Igor
0
 
Edo082297Author Commented:
Hi Igor
  I already do exactly that, so yes, I will implement it that way. Post an answer, I will award you the points if you like.

Regards,
Edo
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.