blah blah blah is here! blah blah » Close

up1down
link

I was trying to create a utility which should monitor a user specified drive.... but while troubleshooting I'm discovering that as I try to fetch (a particular) network drive..... my application is suffocated to death. The wait cursor (not responding) thing appears eternally.

I tried to do something like this:

On "go" Button_Click event
{
button1.Text = "Wait...";
FileSystemWatcher fsw = new FileSystemWatcher();
fsw.Path = textBox1.Text;
FillTreeControl(textBox1.Text);
treeView1.TopNode.Expand();
fsw.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
fsw.Changed += new FileSystemEventHandler(OnChanged);
fsw.Created += new FileSystemEventHandler(OnCreated);
fsw.Deleted += new FileSystemEventHandler(OnChanged);
fsw.Renamed += new RenamedEventHandler(OnRenamed);
fsw.EnableRaisingEvents = true;
this.Text = "Watching " + textBox1.Text;
}


and when everything is finished then I change back button1.Text = "Go";

But when the application is asked to fetch a network drive like J:\common..... it enters into a comma.

The worst thing is that the Button1's text does not changes to "Wait" and the application is murdered, to a user it's not at all clear what had happened to the window. what button1.Text does not changes before the application tries to fetch anything from network drive?

Can I break the operation after 120seconds of "not responding" state? How can I tackle this thing?

Code for filling the treeview is:
treeView1.Nodes.Clear();
TreeNode _node = new TreeNode(_r);
treeView1.Nodes.Add(_node);
FillSubTree(_node, _node.Text);


I think the prob is in the code used for validating the path:
bool _ret = false;
string[] _drives = Environment.GetLogicalDrives();
if (_p.Substring(1, 1).ToUpper() != ":")
throw (new DirMalformedException());
string _root = _p.Substring(0, 1).ToUpper();
foreach (string _device in _drives)
{
if (_root == _device.Substring(0, 1))
_ret = true; // normally not enough drives avail to worry about efficiency here
}
if (!_ret)
throw (new DirDriveException());


Hopes this helps u find the solution of my prob.


Second Edit:
Here's the problem I think... this is the code I was going through line-by-line... and feel that filling the sub tree also have something to do
DirectoryInfo _dirInfo = new DirectoryInfo(_full);
DirectoryInfo[] _subDirs = _dirInfo.GetDirectories();
foreach (DirectoryInfo _subDirInfo in _subDirs)
{
{
TreeNode _subNode = new TreeNode(_subDirInfo.Name);
_parent.Nodes.Add(_subNode);
FillSubTree(_subNode, _subDirInfo.FullName);
}
}
FileInfo[] _files = _dirInfo.GetFiles();
foreach (FileInfo _file in _files)
{
if ((_file.Attributes & FileAttributes.System & FileAttributes.Hidden) != 0)
{
TreeNode _fileNode = new TreeNode(_file.Name);
_parent.Nodes.Add(_fileNode);
}
}


As I typed "C:\" to watch.... I had to face lots of prompts which were due to access problems. Ex. windows, system32, and similar directories.

But if I type "C:" to watch... then the tree & sub tree fills properly.

Spooky.

vulpes
17279

Are you sure that it's not the filling of the TreeView control that's causing the UI to freeze rather than the activities of the FileSystemWatcher? If that is in fact the problem, then you can call the TreeView's BeginUpdate method to prevent repainting until the EndUpdate method is called. See http://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.beginupdate.aspx.

gsvirdi
412

had checked again that this prob comes only in some particular drives, other drives works fine and TreeView is filled instantly. As I said: the 1st line textBox1.Text = "Wait"; is also not working... and the Form freezes.

last answered one year ago

3 answers

up2down
link

you have to set the file watching up in another thread. you're setting it up in your UI thread which blocks your form from redrawing itself.

gsvirdi
412

Please pardon my unability to figureout the code u suggested. I'm not at gud in threads, I need a example code to undertand that thing :(

up2down
link

It sounds like the repainting of the TreeView is definitely your problem, if it's working OK when the drive only contains a few files.

So I'd try:

//On "go" Button_Click event
{
button1.Text = "Wait...";
FileSystemWatcher fsw = new FileSystemWatcher();
fsw.Path = textBox1.Text;
treeView1.BeginUpdate(); // suspend repainting
FillTreeControl(textBox1.Text);
treeView1.EndUpdate(); // re-enable repainting
treeView1.TopNode.Expand();
fsw.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
fsw.Changed += new FileSystemEventHandler(OnChanged);
fsw.Created += new FileSystemEventHandler(OnCreated);
fsw.Deleted += new FileSystemEventHandler(OnChanged);
fsw.Renamed += new RenamedEventHandler(OnRenamed);
fsw.EnableRaisingEvents = true;
this.Text = "Watching " + textBox1.Text;
}

gsvirdi
412

fetching the tree appears to be faster, but the real prob remains. The utility is not able to fetch the directory. Please see my "Second Edit". I have also included the code which (I think) is filling the sub tree of the main tree.

gsvirdi
412

ContextSwitchDeadlock was detected (FillTreeControl(textBox1.Text);).......................... The CLR has been unable to transition from COM context 0x21cec8 to COM context 0x21d038 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

up1down
link

I can't say I'd realized it before but if you pass a drive letter (such as C:) to the DirectoryInfo constructor, it will assume you mean the user's 'home' directory. If you do:

MessageBox.Show(_dirInfo.FullName);

you'll see what I mean. This will probably generate a manageable number of files for the TreeView to handle even allowing for nested subdirectories.

On the other hand, if you pass it a root directory (such as c:\), then that's exactly what you'll get and the code will then have to plough recursively through every file on c:\ drive, filling the TreeView as it does so, which will take 'years' if there are several hundred thousand files on that drive like there are on mine. Worse still some of the files will have accessibility problems.

Also, the FileSystemWatcher is currently only watching the 'top level' directory because you haven't set the IncludeSubDirectories property to 'true'. If you did set it to 'true', then the FileSystemWatcher's internal buffer could easily be swamped with changes and cease to function correctly.

So, if I were you, I'd consider limiting the application to 'top level' directories only and (preferably) prevent the user from choosing a system directory with inaccessible files.

If you don't want to do that, then you could use a timer to abort the operation if, say, the treeview hasn't filled within 30 seconds or you could count the number of nodes created and abort the operation when the count reaches a certain figure - you'd have to try out various maxima to determine the optimal limit.

Feedback