Problem with wxFileSystemWatcher: Does not recognize modif. Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
extreme001
I live to help wx-kind
I live to help wx-kind
Posts: 192
Joined: Fri Dec 22, 2006 9:17 am
Location: Germany
Contact:

Problem with wxFileSystemWatcher: Does not recognize modif.

Post by extreme001 »

Hi!

I'm testing with wx 2.91 and wxFileSystemWatcher. I want to oberve a dir and notify my app if a file was created or modified.

Here's my wxFileSystemWatcher-Class:

My header-file:

Code: Select all

#pragma once
#ifndef HHFILEWATCHER_H
#define HHFILEWATCHER_H

extern const wxEventType wxEVT_CMD_JOB_STATUS;
extern const wxEventType wxEVT_CMD_JOB_STATUS_VOID_PTR;

#include <wx/fswatcher.h>
#include "ProviderFinder.h"

class HHFileWatcher : public wxFileSystemWatcher
{
public:
	HHFileWatcher(void);
	~HHFileWatcher(void);
	ProviderFinder ProviderDef;
	void SendEvent(int i, wxString &msg);
	wxString tmpfilename;

protected:
	void OnChange(int changeType, const wxFileName& path, const wxFileName& newPath);
	void OnWarning(const wxString &errorMessage);
	void OnError(const wxString &errorMessage);
};

#endif // HHFILEWATCHER_H
AND here's the cpp

Code: Select all

#include "HHFileWatcher.h"


HHFileWatcher::HHFileWatcher(void)
{

}


HHFileWatcher::~HHFileWatcher(void)
{
	
}

void HHFileWatcher::OnChange(int changeType, const wxFileName& path, const wxFileName& newPath)
{
	if( (changeType != wxFSW_EVENT_DELETE) || (changeType != wxFSW_EVENT_ERROR) || (changeType != wxFSW_EVENT_WARNING) || (changeType != wxFSW_EVENT_ACCESS) )
	{
		if( path.GetExt().Find(_T("txt")) > wxNOT_FOUND )
		{
			if(ProviderDef.GetProviderFromFile(path.GetFullPath()) > 0)
			{
				tmpfilename = wxString::Format(_T("FILE_TO_PARSE:%s"), path.GetFullPath());
				SendEvent(0, tmpfilename);
			}
		}
	}
}

void HHFileWatcher::OnWarning(const wxString &errorMessage)
{

}

void HHFileWatcher::OnError(const wxString &errorMessage)
{

}

void HHFileWatcher::SendEvent(int i, wxString &msg)
{
	if (GetOwner()) {
		wxCommandEvent e(wxEVT_CMD_JOB_STATUS);
		e.SetInt(i);
		e.SetString(msg);
		GetOwner()->AddPendingEvent(e);
	}
}
Then in another class, a wxPanel derived i use the following code in the constructor:

Code: Select all


FileWatcher = new HHFileWatcher();
FileWatcher->SetOwner(this);

wxFileName dirname( "C:\wurst", "" );
FileWatcher->Add(wxFileName::DirName("C:\wurst"), wxFSW_EVENT_ALL);

The problem is: after setting the breakpoint in OnChange of my wxFileSystemWatcher-derived class and creating a file in C.\Wurst the breakpoint is not reached, no recognize.

Any idea what could be the error? Am I doing it wrong?

Thank you very much
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

I've never used this class, but from the documentation i'd say you should remove the line "FileWatcher->SetOwner(this);"

You use call this when you want the events to be send to another wxEvtHandler, but in your case you handle the changes by overriding wxFileSystemWatcher::OnChange()
Use the source, Luke!
extreme001
I live to help wx-kind
I live to help wx-kind
Posts: 192
Joined: Fri Dec 22, 2006 9:17 am
Location: Germany
Contact:

Post by extreme001 »

Thank you!

I removed the OnChange from the HHfilewatcher-class and set it in my Panel-Class and used SetOwner. No success.

i added this to my class (the Setowner)

Code: Select all

protected:
        void OnChange(int changeType, const wxFileName& path, const wxFileName& newPath);
        void OnWarning(const wxString &errorMessage);
        void OnError(const wxString &errorMessage);
Does anyone know how to solve it?
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

I have also never used this class, Nevertheless, I don't think overriding these functions in the Owner is going to work as your panel is not derived from wxFileSystemWatcher. I think you should begin with what FSWatcher sample does:
1. create an instance of wxFileSystemWatcher in your Panel
2. set its owner to the Panel
3. create void OnFileSystemEvent(wxFileSystemWatcherEvent& event) function in the Panel
4. after you instantiate the Watcher call Bind(wxEVT_FSWATCHER, &Panel::OnFileSystemEvent, this)

By the way, during running the FSWatcher sample I have noticed, that despite it calls Add() it behaves as it called AddTree()? In another words, if I add "C:\" it seems all the folders under the added one are being watched, not just its immediate children, e.g. I do get notifications like
MODIFY C:\Windows\System32\config\SOFTWARE
CREATE C:\Users\911251\AppData\Roaming\Mozilla\Firefox\Profiles\gkz5cq0q.default\sessionstore-1.js
I am going to look more into this issue later.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

Well, *that* can't work in any case. If you put the methods in the panel class, you need to set the event table accordingly or use Connect() like with any other event.

Overriding the methods can only work if you derive from wxFileSystemWatcher like in your initial approach.
Use the source, Luke!
extreme001
I live to help wx-kind
I live to help wx-kind
Posts: 192
Joined: Fri Dec 22, 2006 9:17 am
Location: Germany
Contact:

Post by extreme001 »

Thanks for your answers.

If i use the derived one, overriding the method, ok, i did try. The point is that the internals of wxFileSystemWatcher works, if i set breakpoints i can see that an event is sent to the owner, but the overriden OnChange never got hit. The same problem when i use the bind-Method, the Event never arrives in my panel.

that's my code so far:

Code: Select all

// in my header file
wxFileSystemWatcher * FileWatcher;

//in my constructor in cpp of panel
FileWatcher = new wxFileSystemWatcher();
	FileWatcher->SetOwner(this);
	FileWatcher->Bind(wxEVT_FSWATCHER, &ImportDlg::OnFileSystemEvent, this); 

FileWatcher->Add(wxFileName::DirName("C:\\wurst"), wxFSW_EVENT_ALL);


//This is my event implementation
void ImportDlg::OnFileSystemEvent(wxFileSystemWatcherEvent& event)
{
	int i= 0;
	i++; // breakpoint never active
}

An the internals of wxFileSystemWatcher are ok, i hit my breakpoint after modifying a file in my directory. But OnFileSystemEvent() is never hit.

Any other ideas? More code?


Thank you very much!
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

Try replacing

Code: Select all

FileWatcher->Bind(wxEVT_FSWATCHER, &ImportDlg::OnFileSystemEvent, this); 
with

Code: Select all

Bind(wxEVT_FSWATCHER, &ImportDlg::OnFileSystemEvent, this); 
assuming the code is run within your ImportDlg constructor, I'm somewhat confused because you've also mentioned a panel (as in wxPanel?). I have to admit that I don't really understand "I hit my breakpoint after modifying a file in my directory. But OnFileSystemEvent() is never hit." - the breakpoint is set in that very function, right?

As I'm also still very new to wxWidgets, I'm not sure if the event doesn't get blocked somewhere due to (I presume) ImportDlg running in modal mode.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

BTW: I just checked the sources, overriding the methods can't work, they're not even members of the base class. The documentation is wrong there.

Maybe they planed to implement it that way, but never did ;)
Use the source, Luke!
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

doublemax wrote:BTW: I just checked the sources, overriding the methods can't work, they're not even members of the base class. The documentation is wrong there.;)
I've also noticed that, together with some other issues with this class, so I'm going to create a ticket.
extreme001
I live to help wx-kind
I live to help wx-kind
Posts: 192
Joined: Fri Dec 22, 2006 9:17 am
Location: Germany
Contact:

Post by extreme001 »

OMG...stupid. Shame on me. Of course, the event has to map to function. Thank you VERY much!
extreme001
I live to help wx-kind
I live to help wx-kind
Posts: 192
Joined: Fri Dec 22, 2006 9:17 am
Location: Germany
Contact:

Post by extreme001 »

BTW: I just checked the sources, overriding the methods can't work, they're not even members of the base class. The documentation is wrong there.
Saw it, too... :D

Now wonder that it doesn't work that way.
MoonKid
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 543
Joined: Wed Apr 05, 2006 9:39 am
Contact:

Post by MoonKid »

PB wrote:I've also noticed that, together with some other issues with this class, so I'm going to create a ticket.
Can you give us a ticket ID for that?
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

The list of issues I have found is here:
http://trac.wxwidgets.org/ticket/12847#comment:13
MoonKid
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 543
Joined: Wed Apr 05, 2006 9:39 am
Contact:

Post by MoonKid »

Is it correct if I say that under MSW (Win7) it is only possible to watch directories NOT files explicite?

Because lines like this

Code: Select all

Add( wxFileName("D:\\test.txt"), wxFSW_EVENT_ALL);
cause in this error

Code: Select all

Unable to set up watch for "D:\test.txt". Error 0: Der Vorgang wurde beendet.
Only adding directories work her. Is there still a ticket ID for this bug?
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

I believe I mentioned it several times in various places of the ticket. E.g. in bullet 4 in Issue 3 or in my proposal for changing wxFileSystemWatcher interface - both in my last comment on the ticket.

MSW implementation of wxFileSystemWatcher is based around Windows function ReadDirectoryChangesW, which allows to track only contents of a directory, not individual files.

By the way, as I guess most of use here don't understand German (or is it Dutch?), it might be useful to provide English translation of errors. Thank you.
Post Reply