Skip to content

Instantly share code, notes, and snippets.

@NoxArt
Created January 16, 2012 19:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NoxArt/1622439 to your computer and use it in GitHub Desktop.
Save NoxArt/1622439 to your computer and use it in GitHub Desktop.
Script to launch given shell command on directory/file change
/**
* Beholder
*
* @author Jiri "NoxArt" Petruzelka | www.noxart.cz | petruzelka@nox-art.cz
* @author Microsoft
*
* @filesource
*
* @link http://msdn.microsoft.com/en-us/library/windows/desktop/aa365261(v=vs.85).aspx
*/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <string>
using std::string;
string onChangeHandler;
bool debug = false;
void DirectoryChanged(LPTSTR);
void TreeChanged(LPTSTR);
void WatchDirectory(LPTSTR);
int _tmain(int argc, TCHAR *argv[])
{
if(argc != 3 && argc != 4)
{
_tprintf(TEXT("Usage: %s <dir> <runOnChange> [debug]\n"), argv[0]);
return 0;
}
debug = (argc == 4);
if( debug )
_tprintf(TEXT("[Beholder: running in DEBUG mode]"));
onChangeHandler = string(argv[2]);
WatchDirectory(argv[1]);
return 0;
}
void WatchDirectory(LPTSTR lpDir)
{
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];
TCHAR lpDrive[4];
TCHAR lpFile[_MAX_FNAME];
TCHAR lpExt[_MAX_EXT];
_splitpath(lpDir, lpDrive, NULL, lpFile, lpExt);
lpDrive[2] = (TCHAR)'\\';
lpDrive[3] = (TCHAR)'\0';
// Watch the directory for file creation and deletion.
dwChangeHandles[0] = FindFirstChangeNotification(
lpDir, // directory to watch
TRUE, // do watch subtree
FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
{
printf("\n ERROR: FindFirstChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
// Watch the subtree for directory creation and deletion.
dwChangeHandles[1] = FindFirstChangeNotification(
lpDrive, // directory to watch
TRUE, // watch the subtree
FILE_NOTIFY_CHANGE_DIR_NAME); // watch dir name changes
if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
{
printf("\n ERROR: FindFirstChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
// Make a final validation check on our handles.
if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
{
printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
ExitProcess(GetLastError());
}
// Change notification is set. Now wait on both notification
// handles and refresh accordingly.
while (TRUE)
{
// Wait for notification.
if(debug)
printf("\nWaiting for notification...\n");
dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
FALSE, INFINITE);
switch (dwWaitStatus)
{
case WAIT_OBJECT_0:
// A file was created, renamed, or deleted in the directory.
// Refresh this directory and restart the notification.
DirectoryChanged(lpDir);
if ( FindNextChangeNotification(dwChangeHandles[0]) == FALSE )
{
printf("\n ERROR: FindNextChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
break;
case WAIT_OBJECT_0 + 1:
// A directory was created, renamed, or deleted.
// Refresh the tree and restart the notification.
TreeChanged(lpDrive);
if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE )
{
printf("\n ERROR: FindNextChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
break;
case WAIT_TIMEOUT:
// A timeout occurred, this would happen if some value other
// than INFINITE is used in the Wait call and no changes occur.
// In a single-threaded environment you might not want an
// INFINITE wait.
printf("No changes in the timeout period.\n");
break;
default:
printf("ERROR: Unhandled dwWaitStatus.\n");
ExitProcess(GetLastError());
break;
}
}
}
void DirectoryChanged(LPTSTR lpDir)
{
if( debug )
_tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
else
system(onChangeHandler.c_str());
}
void TreeChanged(LPTSTR lpDrive)
{
if( debug )
_tprintf(TEXT("Directory tree (%s) changed.\n"), lpDrive);
else
system(onChangeHandler.c_str());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment