User 5842
User 5842

Reputation: 3029

Windows Event Hooks for File Saved

Every time I save a certain script file I'm working on in NotePad++, I am required to upload the changes to our server so that we can deploy the changes to various machines.

I sometimes forget to upload the changes after refactoring my code in NotePad++ and I was wondering if there was a way for me to create a simple application that would listen for a 'Save' event and automatically upload the file for me.

I am currently running on a Windows OS and was hoping to do this using C++. I'd like to explore Windows Events and possibly tie into an event hook to accomplish this. Any other languages would be welcome as well.

Any ideas or tips?

Here is my code thus far following Josh's recommendations below:

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

void RefreshDirectory(LPTSTR);
void WatchDirectory(LPTSTR);

void _tmain(int argc, TCHAR *argv[])
{
    if (argc != 2)
    {
        _tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);
        return;
    }

    WatchDirectory(argv[1]);
}

void WatchDirectory(LPTSTR lpDir)
{
    DWORD dwWaitStatus;
    HANDLE dwChangeHandles[2];
    TCHAR lpDrive[4];
    TCHAR lpFile[_MAX_FNAME];
    TCHAR lpExt[_MAX_EXT];

    _tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);

    lpDrive[2] = (TCHAR)'\\';
    lpDrive[3] = (TCHAR)'\0';

    // Watch the directory for file creation and deletion. 

    dwChangeHandles[0] = FindFirstChangeNotification(
        lpDir,                         // directory to watch 
        FALSE,                         // do not watch subtree 
        FILE_NOTIFY_CHANGE_LAST_WRITE); // watch file name changes 

    if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
    {
        printf("\n ERROR: FindFirstChangeNotification function failed.\n");
        ExitProcess(GetLastError());
    }

    // Make a final validation check on our handles.

    if ((dwChangeHandles[0] == 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.

        printf("\nWaiting for notification...\n");

        // Waits until the specified object is in the signaled state or 
        // the time-out interval elapses.
        // Because our second parameter is set to INFINITE, the function will
        // return only when the object is signaled.
        dwWaitStatus = WaitForSingleObject(dwChangeHandles, INFINITE);

        switch (dwWaitStatus)
        {
            // Our return value, WAIT_OBJECT_0 signifies that the first object
            // signaled the event.
            case WAIT_OBJECT_0:

                // A file was created, renamed, or deleted in the directory.
                // Refresh this directory and restart the notification.

                RefreshDirectory(lpDir);
                if (FindNextChangeNotification(dwChangeHandles[0]) == 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("\nNo changes in the timeout period.\n");
                break;

            default:
                printf("\n ERROR: Unhandled dwWaitStatus.\n");
                ExitProcess(GetLastError());
                break;
        }
    }
}

void RefreshDirectory(LPTSTR lpDir)
{
    // This is where you might place code to refresh your
    // directory listing, but not the subtree because it
    // would not be necessary.

    _tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
}

Upvotes: 0

Views: 1786

Answers (2)

root
root

Reputation: 59

Think about writing a NP++ plugin instead.

You can register your plugin to be notified whenever a file is saved or about to be saved using NPPN_FILESAVED or NPPN_FILEBEFORESAVE.

Please look at this link:

http://docs.notepad-plus-plus.org/index.php/Messages_And_Notifications

Upvotes: 0

user197015
user197015

Reputation:

You can monitor the filesystem for changes using FindFirstChangeNotification. When you call this function, you get a HANDLE back. You can wait on that handle using WaitSingleObject (or similar). When the wait returns, you can use ReadDirectoryChanges to figure out exactly what happened. If whatever happens matches some event or change you care about for your file, you can take the appropriate action... otherwise ignore the event.

Because you'll be waiting (and thus blocking the thread), you may want to perform this work on a worker thread if you want your program in question to be doing anything else.

A simple way to start might be to listen for events with the FILE_NOTIFY_CHANGE_LAST_WRITE filter; this will release your wait when files in the monitored directory are written to.

Note that not all programs save files in the same way; some open the existing file and write to it, others delete it and replace, or some combination thereof (first writing to a temporary file, then swapping it with the original). Consequently it may not be as straightforward as waiting for just last-write notifications to accomplish precisely what you're after.

Upvotes: 1

Related Questions