A Stronger Defense Through Better Software
A Service Provided By
George Chastain, Huntsville, Alabama

Résumé
Home What's New? About Security Contact Submit Content Disclaimers

Search This Site


powered by FreeFind

Targeted Web Search

Departments
Development

Test, QA & Safety
The Biz

Information Security

Joint Resources

General
CDR
Systems
Weapons 101
DoD Links

Media
Office Resources
Defense News
Defense Magazines

Tech & World News

Reader's Corner

Books

 ©2006 G. Chastain

GCShellNotificationDLL

Developer's Guide

Version 1.0

Developed By: George E. Chastain

All rights reserved.

Download the Visual C++ Project Source (Self-extracting EXE)

Overview

The GCShellNotificationDLL provides the developer with the ability to easily incorporate Change Notification Events into an application. This allows an application to be notified if there are any changes to a file or folder made in any folder on the system.

Figure 1 Notification Flow

The GCShellNotificationDLL provides the ability to watch as many specific directories (and their subdirectories) as you wish. So if your application needs to be notified of a change in more than one location on the system, you can easily do so without having to watch the entire system, receiving notification every time something changes that you are not interested in. You also have the capability to specify different messages for each folder or directory tree that you are watching so that you may code your application to take different actions based on the folder or tree in which the change occurred. This capability is illustrated in Figure 2 Separate Messages.

Figure 2 Separate Messages

In order for a client to receive a notification of a change occurring in one or more specified folders or trees, the client must create at least one object of class CGCShellNotification defined by the header file GCShellNotify.h. This object will be used to install notification events for the folders/trees. Each CGCShellNotification object is designed to notify a single window in the client when a change occurs in a folder/tree. If the developer needs to have notifications sent to more than one window, the client can either redirect messages to the other windows or the developer may create more than one CGCShellNotification object, one for each window that must be notified. This is illustrated in Figure 3 CGCShellNotification Objects.

Figure 3 CGCShellNotification Objects

The client installs Notification Events for each folder or tree that is to be watched via calls to the method CGCShellNotification::CreateNotification(). The client may terminate notifications for any previously-specified folder or tree by calling the method CGCShellNotification::TerminateNotification(). Both of these methods are described in detail later.

Interface

GCShellNotificationDLL manages the worker threads necessary for monitoring the directories so the application developer does not have to worry about this either. You may monitor as many separate directory trees as you like.

To set up your application to monitor a folder or directory tree, you will first need to create and object of class CGCShellNotification. The class is defined in the header file GCShellNotify.h.

With the exception of the class constructor and destructor, all of the methods for class CGCShellNotification return a status of type GC_NOTIFY_STATUS. The status that is returned by the class methods will be one of the following:

GC_NSUCCESS

The requested operation succeeded.

GC_FOLDER_DOES_NOT_EXIST

The specified folder does not exist on the system.

GC_INITIALIZATION_FAILED

The GCShellNotification object was not created or did not initialize properly. That is, a failure occurred in the constructor.

GC_NO_FOLDERS_WATCHED

There are no folders currently being watched.

GC_FOLDER_ALREADY_WATCHED

The specified folder is already being watched.

GC_FOLDER_NOT_BEING_WATCHED

There are folders being watched but the folder specified is itself not being watched.

GC_WATCH_CREATE_FAILED

Unknown failure attempting to create a watch on the specified folder.

The prototype for the class constructor is as follows:

CGCShellNotification();

No copy constructor or assignment operator are exported for this class. It is suggested that you do not create more than one object of this class per process, as it would be wasteful of resources and unnecessary. Also, the client must specify a pointer to a window that is to receive the folder notifications.

Once you have created a notification object, you may use it to set watch as many separate folders or directory trees as you wish. The method to do this is CreateNotification() and its prototype is

GC_NOTIFY_STATUS CreateNotification(GC_PATHNAME_TYPE& FolderToWatch,
				    BOOL bWatchSubfolders,
                                    DWORD WatchEvents,
                                    CWnd* pTargetWindow,
                                    UINT MessageID,
                                    void (*pf)(LPVOID),
                                    LPVOID pData);

The first parameter, FolderToWatch, is the completely qualified path to the folder you wish to watch. Or, if you wish to watch an entire directory tree, you would pass the fully qualified path to the root of that tree in this parameter. The second parameter, bWatchSubfolders, indicates if you wish to watch only the folder specified (FALSE) or that folder and all folders beneath it (TRUE). The default is to watch the entire tree under the specified folder. The third parameter, WatchEvents, specifies which events you wish to watch for in the indicated folder or tree. This may be any combination of the following flags:

GC_FILENAME

Any file name change in the watched directory or subtree causes a change notification wait operation to return. Changes include renaming, creating, or deleting a file name.

GC_DIRNAME

Any directory-name change in the watched directory or subtree causes a change notification wait operation to return. Changes include creating or deleting a directory.

GC_ATTRIBUTE

Any attribute change in the watched directory or subtree causes a change notification wait operation to return.

GC_SIZE

Any file-size change in the watched directory or subtree causes a change notification wait operation to return. The operating system detects a change in file size only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.

GC_LAST_WRITE

Any change to the last write-time of files in the watched directory or subtree causes a change notification wait operation to return. The operating system detects a change to the last write-time only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.

The fourth parameter, pTargetWindow, is an optional pointer to a window that is to receive notification messages when a folder event occurs.

The fifth parameter, MessageID, is the ID of the message -- typically an application-defined message -- that is to be sent to the window specified in the constructor, when any of the indicated changes are detected in the specified folder. This parameter is ignored if pTargetWindow == NULL.

The sixth parameter to CreateNotification() is a pointer to a function of type void (*pf)(LPVOID). This parameter allows the client to specify a callback function to be called when a folder event occurs. This parameter is optional.

The seventh and final parameter, pData, is an LPVOID pointer to data that is to be passed to the callback function pointed to by the sixth parameter. The pData parameter is ignored if the pointer to the callback function is NULL.

The client must specify either a window to notify via the pTargetWindow parameter or a callback function or both. The call will fail if these conditions are not met.

The client application may also obtain a list of all folders currently being watched. This list is obtained by a call to the GetWatchedFolders() method shown below:

GC_NOTIFY_STATUS GetWatchedFolders(WATCHEDFOLDERSVECTOR& Folders);

The GetWatchedFolders() method returns a vector of type WATCHEDFOLDERSVECTOR. The vector elements are of type struct WATCHEDFOLDER as shown:

typedef struct
{
     GC_PATHNAME_TYPE Path;
     DWORD Filters;
     BOOL bSubFolders;
     CWnd* pTargetWindow;
     UINT uMessageID;
     void (*pCallbackFunction)(LPVOID);
     LPVOID CallbackFunctionArg;
} WATCHEDFOLDER;

   

The member Path is the path specified in a previous call to CreateNotification(). The Filters is the flags specified in the WatchEvents parameter of the call to CreateNotification(). The bSubFolders member indicates the value of the parameter bWatchSubfolders of the call to CreateNotification(). The pTargetWindow member is the window to which notifications are to be sent. The uMessageID member indicates the message ID specified in the call to CreateNotification(). The pCallbackFunction member is a pointer to a callback function that is to be called when a notification event occurs. And finally, the CallbackFunctionArg member is a pointer to data that is to be passed to the callback function pointed to by pCallbackFunction. Note that either the pTargetWindow member or the pCallbackFunction member may be NULL but not both. The uMessageID member is ignored if pTargetWindow is NULL. Similarly, the CallbackFunctionArg member is ignored if pCallbackFunction is NULL.

To terminate watching all folders, simply destroy the CGCShellNotification object or allow it to go out of scope. All notifications will be terminated when the object is destroyed. The client also has the ability to terminate the current notifications for any previously-specified folder. This may be accomplished by calling the method TerminateNotification():

GC_NOTIFY_STATUS TerminateNotification(GC_PATHNAME_TYPE& Folder);

If, for example, you had set up a watch on the folder "C:\My Documents\" by calling CreateNotification() and you wished to stop watching just that folder, you would simply call TerminateNotification() and pass it that path.

The client may also see if a particular folder is currently being watched. This may be accomplished by calling

GC_NOTIFY_STATUS LookupFolder(GC_PATHNAME_TYPE& Folder,
                              WATCHEDFOLDER& FolderSettings);

If the folder (or tree) specified in Folder is currently being watched for any changes, the method will return TRUE and return the settings for that folder/tree in the FolderSettings parameter of type struct WATCHEDFOLDER.

The client may simply check to see if there are currently any folders being watched by calling

GC_NOTIFY_STATUS CountOfFoldersBeingWatched(UINT& Count)

If any folders are being watched, CountOfFolders() will return GC_NSUCCESS and set Count to the number of folders currently being watched. If no folders are currently being watched, Count will be set to 0 and the function will return GC_NO_FOLDERS_WATCHED.

How To Use GCShellNotificationDLL In Your Visual C++ 6.0 Project

You may call this DLL from either an application or another DLL. The steps required to use this DLL are as follows:

  1. You must specify that your project (application or DLL) link with the Import Library for GCShellNotificationDLL.
    1. Select Project | Settings from within Visual C++.
    2. Select the "Link" tab.
    3. In the "Object/library modules:" edit box, enter the path to the GCShellNotificationDLL.lib delivered with the DLL.
  2. In the source file where you will declare/create a CGCShellNotification object, include the header file GCShellNotify.h.
  3. After the CGCShellNotification class object is created, call CreateNotification() to create a Notification Event for a specified folder or tree.
  4. Build your application or DLL.

Thread And Process Safe

The CGCShellNotification provides thread safety at the class level. All methods to the class will momentarily block all but one thread from executing the method at a time. The duration of the blocking will be minuscule.

The DLL is also process safe. The developer does not have to worry about more than one process loading the DLL simultaneously.

Special Considerations

When calling CreateNotification(), you should remember that some Windows system folders contain files that are updated frequently by the operating system. If you call CreateNotification() to watch one of these folders your client application may receive a large volume of notification messages. It is also possible that third-party applications could frequently update the contents of a folder or file within a path that you are watching. Keep this in mind when designing your client application.

This version of GCShellNotificationDLL creates a separate thread for monitoring each individual folder or tree. That is, if you call CreateNotification() for a particular folder, then call CreateNotification() for a different directory tree, perhaps on another drive, then two separate threads will be created, one for each call to CreateNotification(). Each thread must make a call to WaitForMultipleObjects() (see MSDN). Microsoft imposes a limit to the number of wait object that WaitForMultipleObjects() will wait on. Currently, this value, MAX_WAIT_OBJECTS, is defined to be 64 by winnt.h. By creating a separate thread for each folder monitored, it was possible to provide a simple workaround to this system-imposed limit. Therefore, you should consider this if your application will create a large number of threads. If you find that two or more of the folders you wish to watch are under a common folder that has small trees or trees that will not be modified/updated frequently by other processes, you should consider call CreateNotification() just for the common folder and passing TRUE for the bWatchSubfolders parameter. This is illustrated in Figure 4 GCShellNotification Threading Model

Figure 4 GCShellNotification Threading Model

Download the Visual C++ Project Source (Self-extracting EXE)

Top