Click here to Skip to main content
Click here to Skip to main content

Track File Activites

By , 12 Feb 2013
 
Track File Activites

Introduction

This application will demonstrate how to effectively use FileSystemWatcher. The application is flexible enough for user configuration. The user needs to provide the track path which s/he wants to keep a track of and provide another work path where log file will be maintained daily. Folders will be created for each day and log will be maintained. This will give user the flexibility to view previous day's log without any fuzz. Note that once this path has been defined, it will be stored in System Registry, so the user does not have to feed in the path every time s/he opens the application, it will be automatically retrieved from registry. The user can choose the option for tracking subfolders or not. S/he can filter using various options, like "*.*, *win.*, a*b.c* and so on...". Notify filter can also be configured based on user's need, like "FileName, DirectoryName, Attributes, Size, LastWrite, LastAccess, CreationTime, Security".

Track File Activities Log

Track File Activites Log

This window helps to view the log that has been created by TrackFileActivity for each day. Usually the generated log for each day is huge and it is a very tedious job to view all these logs. The user has the option to filter the data based on Events, Path, Time. Event can be selected for "Created", "Changed", "Deleted", and "Renamed". Path can be any string which is not case sensitive. Time can filter between start time and end time. The user also has an option for defining Auto Refresh Interval which will refresh the log view based on the filter at the mentioned interval automatically. If s/he wants to manually refresh the log view, then click on Manual Refresh button. The user has the option to click on the column of list view to sort the log/data in ascending or descending order. Each log in the Log View will be grouped by "Create", "Rename", "Delete", and "Change" which will be denoted by colors. By default, the log view will be for present date, but the user has the option to select previous date log files and view them as well. For simplicity, Track File Activities Log window can be opened for only one instance at any given time. That means the user cannot open multiple windows for Track File Activities Log. This will give the learner a good code to handle these situations using user32.dll.

Notify Icon

Notify Icon

Notify Icon can be double clicked to open TrackFileActivities at any instance. The user has the option to right click and open TrackFileActivities options, Track File Activities Log or exit the application. While exiting TrackFileActivities, it will ask for confirmation for exiting the application.

Using the Code

SendMessage

This code demonstrates how to implement USER32.dll and open any window for a single instance at any given time.

//Declare global variable
private int hwdfrmTrackLog;

//Import this function
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);

//Display frmTrackLog if the form is not already opened
if (hwdfrmTrackLog == -1)
{
   frmTrackLog objfrmTrackLog = new frmTrackLog(strWorkPath);
   objfrmTrackLog.Disposed += new EventHandler(frmTrackLog_Disposed);
   hwdfrmTrackLog = objfrmTrackLog.Handle.ToInt32();
   objfrmTrackLog.Show();
}        

public void frmTrackLog_Disposed(object sender, EventArgs e)
{
   //When the form is disposed, set the handle back
   hwdfrmTrackLog = -1;
}

Registry

This code demonstrates how to read/write values in System Registry Key.

using Microsoft.Win32;

//Read from Registry Key if value exists
RegistryKey rk = Registry.LocalMachine;
RegistryKey rkOpenTrack = rk.OpenSubKey("SOFTWARE\\" + 
        "TrackFileActivitesSumit\\TrackPath");
if (rkOpenTrack != null)
{
   txtSetPath.Text = rkOpenTrack.GetValue("Path").ToString();
}

//Write value to Registry Key
RegistryKey rk = Registry.LocalMachine;
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
   txtSetPath.Text = folderBrowserDialog.SelectedPath;
   RegistryKey rkCreate = rk.CreateSubKey("SOFTWARE\\" + 
        "TrackFileActivitesSumit\\TrackPath");
   rkCreate.SetValue("Path", txtSetPath.Text);
}

btnStartTracking_Click

This code demonstrates how to set filters and notify filters and other parameters for FileSystemWatcher. It also checks and sets other controls accordingly.

private void btnStartTracking_Click(object sender, EventArgs e)
{
  try
  {
     if ((txtSetPath.Text.Length != 0) && (txtWorkPath.Text.Length != 0))
     {
         notifyIcon.Text = "Track File Activites [running]";
         btnStartTracking.Enabled = false;
         btnStopTracking.Enabled = true;

         btnSetPath.Enabled = false;
         btnWorkPath.Enabled = false;
         cmbFilters.Enabled = false;
         chkIncludeSubdirectories.Enabled = false;
         gbNotifyFilter.Enabled = false;

         this.fileSystemWatcher.EnableRaisingEvents = false;
         if (chkAttributes.Checked == true)
         {
             fileSystemWatcher.NotifyFilter = 
                fileSystemWatcher.NotifyFilter | NotifyFilters.Attributes;
         }
         if (chkCreationTime.Checked == true)
         {
             fileSystemWatcher.NotifyFilter = 
                fileSystemWatcher.NotifyFilter | NotifyFilters.CreationTime;
         }
         if (chkDirectoryName.Checked == true)
         {
             fileSystemWatcher.NotifyFilter = 
            fileSystemWatcher.NotifyFilter | NotifyFilters.DirectoryName;
         }
         if (chkFileName.Checked == true)
         {
             fileSystemWatcher.NotifyFilter = 
                fileSystemWatcher.NotifyFilter | NotifyFilters.FileName;
         }
         if (chkLastAccess.Checked == true)
         {
             fileSystemWatcher.NotifyFilter = 
                fileSystemWatcher.NotifyFilter | NotifyFilters.LastAccess;
         }
         if (chkLastWrite.Checked == true)
         {
             fileSystemWatcher.NotifyFilter = 
                fileSystemWatcher.NotifyFilter | NotifyFilters.LastWrite;
         }
         if (chkSecurity.Checked == true)
         {
             fileSystemWatcher.NotifyFilter = 
                fileSystemWatcher.NotifyFilter | NotifyFilters.Security;
         }
         if (chkSize.Checked == true)
         {
              fileSystemWatcher.NotifyFilter = 
                fileSystemWatcher.NotifyFilter | NotifyFilters.Size;
         }

         fileSystemWatcher.Path = txtSetPath.Text;
         fileSystemWatcher.Filter = cmbFilters.Text;
         fileSystemWatcher.IncludeSubdirectories = chkIncludeSubdirectories.Checked;
         fileSystemWatcher.EnableRaisingEvents = true;
     }
     else
     {
          MessageBox.Show("Either of the path is not defined. 
    Please define the path for Track File Activities and Working Path for Log.", 
        "Please define Tracking and
    Working path ...", MessageBoxButtons.OK, MessageBoxIcon.Information);
      }
   }
   catch (ArgumentException ae)
   {
       MessageBox.Show(ae.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   }
   catch (Exception ee)
   {
       MessageBox.Show(ee.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   }
}

fileSystemWatcher_Renamed

This code demonstrates how to implement events for FileSystemWatcher and append in a log file. It demonstrates for Rename event which is the same as other events, namely "Create", "Delete", and "Change".

private void fileSystemWatcher_Renamed(object sender, System.IO.RenamedEventArgs e)
{
   StreamWriter sw = File.AppendText(strWorkPath);
   sw.WriteLine(e.ChangeType + "|" + e.OldFullPath + " to " + e.FullPath + 
        "|" + DateTime.Now.ToLongTimeString());
   sw.Flush();
   sw.Close();
}

DisplayLogInListView

This code demonstrates how to implement read log file, apply filter to these data and assign color to each log grouping by "Create", "Rename", "Delete", and "Change".

public void DisplayLogInListView()
{
    try
    {
        timer.Enabled = false;

        if (!File.Exists(txtLogPath.Text.Replace("TrackFileActivities.log", "") +
            "Copy of TrackFileActivities.log"))
        {
            File.Copy(txtLogPath.Text, 
                txtLogPath.Text.Replace("TrackFileActivities.log", "") + 
                    "Copy of TrackFileActivities.log");
        }
        else
        {
            File.Delete(txtLogPath.Text.Replace("TrackFileActivities.log", "") +
                "Copy of TrackFileActivities.log");
            File.Copy(txtLogPath.Text, 
                txtLogPath.Text.Replace("TrackFileActivities.log", "") +
                    "Copy of TrackFileActivities.log");
        }

        listViewLog.Items.Clear();
        Match matchRegEx;
        ListViewItem lvItem;
        string strReadLog = "";
        string[] strReadLogColl;
        TextReader tr = new StreamReader
            (txtLogPath.Text.Replace("TrackFileActivities.log", "") +
                "Copy of TrackFileActivities.log");
        while ((strReadLog = tr.ReadLine()) != null)
        {
            bool boolFlag = false;
            strReadLogColl = strReadLog.Split('|');
            if ((chkCreated.Checked == true) && (strReadLogColl[0] == "Created"))
            {
                matchRegEx = Regex.Match(strReadLogColl[1], txtPath.Text, 
                    RegexOptions.IgnoreCase);
                if (matchRegEx.Success)
                {
                    DateTime dtCompStartTime = Convert.ToDateTime
                        (dtStartTime.Value.ToShortDateString() + " " +
                            strReadLogColl[2]);
                    DateTime dtCompEndTime = Convert.ToDateTime
                        (dtEndTime.Value.ToShortDateString() + " " +
                            strReadLogColl[2]);
                    if ((dtCompStartTime >= dtStartTime.Value) && 
                        (dtCompEndTime <= dtEndTime.Value))
                    {
                        boolFlag = true;
                    }
                }
            }
            if ((chkDeleted.Checked == true) && (strReadLogColl[0] == "Deleted"))
            {
                matchRegEx = Regex.Match(strReadLogColl[1], 
                txtPath.Text, RegexOptions.IgnoreCase);
                if (matchRegEx.Success)
                {
                    DateTime dtCompStartTime = Convert.ToDateTime
                    (dtStartTime.Value.ToShortDateString() + " " +
                    strReadLogColl[2]);
                    DateTime dtCompEndTime = Convert.ToDateTime
                    (dtEndTime.Value.ToShortDateString() + " " +
                    strReadLogColl[2]);
                    if ((dtCompStartTime >= dtStartTime.Value) && 
                    (dtCompEndTime <= dtEndTime.Value))
                    {
                        boolFlag = true;
                    }
                }
            }
            if ((chkRenamed.Checked == true) && (strReadLogColl[0] == "Renamed"))
            {
                matchRegEx = Regex.Match(strReadLogColl[1], txtPath.Text, 
                    RegexOptions.IgnoreCase);
                if (matchRegEx.Success)
                {
                    DateTime dtCompStartTime = Convert.ToDateTime
                    (dtStartTime.Value.ToShortDateString() + " " +
                    strReadLogColl[2]);
                    DateTime dtCompEndTime = Convert.ToDateTime
                    (dtEndTime.Value.ToShortDateString() + " " +
                    strReadLogColl[2]);
                    if ((dtCompStartTime >= dtStartTime.Value) && 
                    (dtCompEndTime <= dtEndTime.Value))
                    {
                        boolFlag = true;
                    }
                }
            }
            if ((chkChanged.Checked == true) && (strReadLogColl[0] == "Changed"))
            {
                matchRegEx = Regex.Match(strReadLogColl[1], 
                    txtPath.Text, RegexOptions.IgnoreCase);
                if (matchRegEx.Success)
                {
                    DateTime dtCompStartTime = Convert.ToDateTime
                    (dtStartTime.Value.ToShortDateString() + " " +
                    strReadLogColl[2]);
                    DateTime dtCompEndTime = Convert.ToDateTime
                    (dtEndTime.Value.ToShortDateString() + " " +
                    strReadLogColl[2]);
                    if ((dtCompStartTime >= dtStartTime.Value) && 
                    (dtCompEndTime <= dtEndTime.Value))
                    {
                        boolFlag = true;
                    }
                }
            }
            lvItem = new ListViewItem(strReadLogColl[0]);
            lvItem.SubItems.Add(strReadLogColl[1]);
            lvItem.SubItems.Add(strReadLogColl[2]);
            if (strReadLogColl[0] == "Created")
            {
                lvItem.ForeColor = Color.Blue;
            }
            else if (strReadLogColl[0] == "Changed")
            {
                lvItem.ForeColor = Color.Brown;
            }
            else if (strReadLogColl[0] == "Deleted")
            {
                lvItem.ForeColor = Color.Red;
            }
            else if (strReadLogColl[0] == "Renamed")
            {
                lvItem.ForeColor = Color.Green;
            }
            if (boolFlag == true)
            {
                listViewLog.Items.Add(lvItem);
            }
        }
        tr.Close();
        File.Delete(txtLogPath.Text.Replace("TrackFileActivities.log", "") + 
            "Copy of TrackFileActivities.log");
        timer.Enabled = true;
        if (listViewLog.Items.Count > 0)
        {
            listViewLog.EnsureVisible(listViewLog.Items.Count - 1);
            listViewLog.Items[listViewLog.Items.Count - 1].Selected = true;
        }
    }
    catch (Exception ee)
    {
        MessageBox.Show(ee.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

Points of Interest

One thing to note is you cannot change the notify filter until and unless you set:

fileSystemWatcher.EnableRaisingEvents = false;

If somebody feels that if the user wants to open the Track File Activities Log window for a second instance, then s/he can do so by sending:

SendMessage(hwdMyForm, 0x0112, 0xF060, 0);

This will dispose the first window and open a new window for the second instance.

Good luck and have a nice day!

History

  • 24th July, 2008: Initial post
  • 13th Feb, 2013: Uploaded code and executable file which was broken

This is the first version. I will be happy if I can add more functionalities and enhancements to the existing one.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

Biswas, Sumit
Tester / Quality Assurance
India India
Member
I am a Performance Engineer, but I like programming. i don't do it as a specialty, but because i love it. anyone who supports source code sharing on the same plane as me.
Anyone who wants to learn more about me can feel free to contact me. Meanwhile, i'd appreciate your feedback. Get in touch sumitsushil@gmail.com
 
* If this article is helpful, please give reputation points.
* Don't forget to tip the waiter with your appreciation.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberJerome Vibert24 Apr '13 - 22:46 
Tested !
Nice program with interesting applications.
QuestionThe only issue I see ...memberGarth J Lancaster12 Feb '13 - 22:47 
...is you dont appear to resolve multiple events for one file - in your own log display, there are multiple change events shown for the NOTEPAD process (the bottom 2 lines)
 
- this means that if you need exclusive access to the file, or to be sure a process has finished writing to it for example, you must be able to deal with this (there are some strategies, I dont think its excessively complex)
 
One of our own - JSOP went into great lengths to demonstrate these issues
 
but good work anyway Smile | :)
Bug404memberasd0z20 Aug '12 - 16:41 
Bin and src links are broken.
GeneralRe: 404memberBiswas, Sumit12 Feb '13 - 23:12 
Solved.
 
Thanks for letting me know.
My instinct is my code

QuestionLogging the username who raised the events ?memberKennethEhmsen22 Jan '12 - 23:51 
Hi, great article one of the best ever.
 
I have a question is it possibel to log the username of who did raise one of the event ?
 

best regards Mr. Ehmsen
AnswerRe: Logging the username who raised the events ?memberBiswas, Sumit12 Feb '12 - 17:51 
I believe its going to be simple. This request is not available in this application. But if I would have done this, then below are the steps I would have followed.
 
Step 1: Get the Computer Name at the init section and store it is global variable.
Step 2: Get the User Name of the user who have logged in at the init section and store it is global variable.
Step 3: Every time an event is logged in the log file, append it with Computer Name and User Name.
 
The request is completed. Please let me know if it looks easy to you?
My instinct is my code

GeneralMy vote of 5memberyamilovesea4 Nov '10 - 21:43 
After testing, I found the application is the best!
GeneralFew things...memberSelvin28 Jul '08 - 0:07 
1. Try to use
if(bool_stmt)
instead
if(bool_stmt == true)
2. Try to use app.config instead registry ... u can even save form state(checkboxes) there Smile | :)
 
...works fascinates me...i can stare it for hours...

GeneralReally Nice Postmembermlpnko27 Jul '08 - 18:09 
Hey Biswas,
 
It is really nice post from you. Though you are performance tester, it is really a nice code coming from you.
 
Hope to see many other posts from you in future dates. Smile | :)
GeneralInterestingmembermerlin98125 Jul '08 - 4:22 
Interesting project. A good addition would be to write an installer that would add the app to the Startup folder or one of the registry startup folders.
 


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LINQ Exchange - Learn about LINQ and Lambda Expressions
Gamehaxors.com - Bots, sploits, and game internals
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 13 Feb 2013
Article Copyright 2008 by Biswas, Sumit
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid