栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

文件钩子实现

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

文件钩子实现

WatchData.h:

#ifndef WATCHDATA_H_

#define WATCHDATA_H_

#include

#include

#include

#include

using namespace std;

typedef void(*ChangeCallback)(int watchID, int action, const WCHAR* rootPath, const WCHAR* filePath);

class WatchData

{

private:

    static int _counter;

    WCHAR* _path;

    int _watchId;

    HANDLE _hDir;

    int _mask;

    bool _watchSubtree;

    DWORD _byteReturned;

    OVERLAPPED _overLapped;

    char _buffer[8196];

    HANDLE _completionPort;

public:

    WatchData();

    WatchData(const WCHAR* path, int mask, bool watchSubtree, HANDLE completionPort);

    virtual ~WatchData();

    const char* getBuffer() { return _buffer; }

    //  FILE_NOTIFY_INFORMATION* getNotifyInfo(){return _notifyInfo;}

    const int getBufferSize() { return sizeof(_buffer); }

    //  const DWORD getBytesReturned() {return _byteReturned;}

    const WCHAR* getPath() { return _path; }

    const int getId() { return _watchId; }

    //  const HANDLE getDirHandle() {return _hDir;}

    //  const int getMask() {return _mask;}

    int watchDirectory();

    // cancel pending watch on the hDir, returns 0 if okay or errorCode otherwise.

    int unwatchDirectory();

};

#endif

Win32FSHook.h:

#ifndef WIN32FSHOOK_H_

#define WIN32FSHOOK_H_

#include

#include

#include

#include

#include

#include "WatchData.h"

using namespace std;

class Event

{

public:

    int _watchID;

    int _action;

    WCHAR* _rootPath;

    WCHAR* _filePath;

    Event(int wd, int action, const WCHAR* rootPath, const WCHAR* filePath)

    {

        _watchID = wd;

        _action = action;

        size_t len1 = wcslen(rootPath);

        size_t len2 = wcslen(filePath);

        _rootPath = new WCHAR[len1 + 1];

        _filePath = new WCHAR[len2 + 1];

        wcsncpy(_rootPath, rootPath, len1);

        _rootPath[len1] = 0;

        wcsncpy(_filePath, filePath, len2);

        _filePath[len2] = 0;

    }

    ~Event()

    {

        delete[] _rootPath;

        delete[] _filePath;

    }

};

class Win32FSHook

{

private:

    static const DWORD DELETE_WD_SIGNAL = 99999997;

    static const DWORD EXIT_SIGNAL = 99999998;

    static Win32FSHook* instance;

    // running flag

    bool _isRunning;

    // thread handle

    HANDLE _mainLoopThreadHandle;

    HANDLE _completionPort;

    // critical seaction

    CRITICAL_SECTION _cSection;

    // watch id 2 watch map

    map _wid2WatchData;

    // Thread function

    static DWORD WINAPI mainLoop(LPVOID lpParam);

    ChangeCallback _callback;

    void watchDirectory(WatchData* wd);

    CRITICAL_SECTION _eventQueueLock;

    HANDLE _eventQueueEvent;

    void postEvent(Event* event);

    HANDLE _eventsThread;

    static DWORD WINAPI eventLoop(LPVOID lpParam);

    queue _eventQueue;

    WatchData* find(int wd);

public:

    static const int ERR_INIT_THREAD = 1;

    Win32FSHook();

    virtual ~Win32FSHook();

    void init(ChangeCallback callback);

    int add_watch(const WCHAR* path, long notifyFilter, bool watchSubdirs, DWORD& error);

    void remove_watch(int watchId);

};

#endif

WatchData.cpp:

#include "WatchData.h"

 //#include "Logger.h"

int WatchData::_counter = 0;

WatchData::WatchData()

{

}

WatchData::~WatchData()

{

    if (_path != NULL) free(_path);

    _hDir = 0;

}

WatchData::WatchData(const WCHAR* path, int mask, bool watchSubtree, HANDLE completionPort)

    :

    _watchId(++_counter),

    _mask(mask),

    _watchSubtree(watchSubtree),

    _byteReturned(0),

    _completionPort(completionPort)

{

    _path = _wcsdup(path);

    _hDir = CreateFileW(_path,

        FILE_LIST_DIRECTORY | GENERIC_READ,

        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,

        NULL, //security attributes

        OPEN_EXISTING,

        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);

    if (_hDir == INVALID_HANDLE_VALUE)

    {

        throw GetLastError();

    }

    if (NULL == CreateIoCompletionPort(_hDir, _completionPort, (ULONG_PTR)_watchId, 0))

    {

        throw GetLastError();

    }

}

int WatchData::unwatchDirectory()

{

    int c = CancelIo(_hDir);

    if (_hDir != INVALID_HANDLE_VALUE) CloseHandle(_hDir);

    if (c == 0)

    {

        return GetLastError();

    }

    else

    {

        return 0;

    }

}

int WatchData::watchDirectory()

{

    memset(_buffer, 0, sizeof(_buffer));

    memset(&_overLapped, 0, sizeof(_overLapped));

    if (!ReadDirectoryChangesW(_hDir,

        _buffer,//<--FILE_NOTIFY_INFORMATION records are put into this buffer

        sizeof(_buffer),

        _watchSubtree,

        _mask,

        &_byteReturned,

        &_overLapped,

        NULL))

    {

        return GetLastError();

    }

    else

    {

        return 0;

    }

}

Win32FSHook.cpp:

#include "Win32FSHook.h"

#include

#include

#include

#include

#include

#include

 //#include "Lock.h"

#include "WatchData.h"

//#include "Logger.h"

Win32FSHook* Win32FSHook::instance = 0;

Win32FSHook::Win32FSHook()

{

    _callback = 0;

    _mainLoopThreadHandle = INVALID_HANDLE_VALUE;

    _eventsThread = INVALID_HANDLE_VALUE;

    _isRunning = false;

    InitializeCriticalSection(&_cSection);

    InitializeCriticalSection(&_eventQueueLock);

    _eventQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

}

void Win32FSHook::init(ChangeCallback callback)

{

    instance = this;

    _callback = callback;

    if (!_isRunning)

    {

        _completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);

        if (_completionPort == NULL)

        {

            throw GetLastError();

        }

        _isRunning = true;

        DWORD dwThreadId;

        LPVOID dwThrdParam = (LPVOID)this;

        _mainLoopThreadHandle = CreateThread(

            NULL,                        // default security attributes

            0,                           // use default stack size 

            Win32FSHook::mainLoop,       // thread function

            dwThrdParam,                // argument to thread function

            0,                           // use default creation flags

            &dwThreadId);                // returns the thread identifier

        if (_mainLoopThreadHandle == NULL)

        {

            throw ERR_INIT_THREAD;

        }

        SetThreadPriority(_mainLoopThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);

        _eventsThread = CreateThread(

            NULL,                        // default security attributes

            0,                           // use default stack size

            Win32FSHook::eventLoop,       // thread function

            dwThrdParam,                // argument to thread function

            0,                           // use default creation flags

            &dwThreadId);                // returns the thread identifier

        if (_eventsThread == NULL)

        {

            CloseHandle(_mainLoopThreadHandle);

            throw ERR_INIT_THREAD;

        }

    }

}

Win32FSHook::~Win32FSHook()

{

    //  debug("+Win32FSHook destructor");

        // terminate thread.

    _isRunning = false;

    SetEvent(_eventQueueEvent);

    PostQueuedCompletionStatus(_completionPort, EXIT_SIGNAL, (ULONG_PTR)NULL, NULL);

    // cleanup

    if (INVALID_HANDLE_VALUE != _mainLoopThreadHandle) CloseHandle(_mainLoopThreadHandle);

    if (INVALID_HANDLE_VALUE != _eventsThread) CloseHandle(_eventsThread);

    CloseHandle(_completionPort);

    DeleteCriticalSection(&_cSection);

    //  debug("-Win32FSHook destructor");

}

void Win32FSHook::remove_watch(int wd)

{

    //  debug("+remove_watch(%d)", wd);

    EnterCriticalSection(&_cSection);

    map ::const_iterator i = _wid2WatchData.find(wd);

    if (i == _wid2WatchData.end())

    {

        //      debug("remove_watch: watch id %d not found", wd);

    }

    else

    {

        WatchData* wd = i->second;

        int res = wd->unwatchDirectory();

        if (res != 0)

        {

            //          log("Error canceling watch on dir %ls : %d",wd->getPath(), res);

        }

        int res2 = _wid2WatchData.erase(wd->getId());

        if (res2 != 1)

        {

            //          log("Error deleting watch %d from map, res=%d",wd->getId(), res2);

        }

        PostQueuedCompletionStatus(_completionPort, DELETE_WD_SIGNAL, (ULONG_PTR)wd, NULL);

    }

    LeaveCriticalSection(&_cSection);

    //  debug("-remove_watch(%d)", wd);

}

int Win32FSHook::add_watch(const WCHAR* path, long notifyFilter, bool watchSubdirs, DWORD& error)

{

    //  debug("+add_watch(%ls)", path);

        // synchronize access by multiple threads

    EnterCriticalSection(&_cSection);

    try

    {

        WatchData* watchData = new WatchData(path, notifyFilter, watchSubdirs, _completionPort);

        if (watchData == 0) throw (DWORD)8; //ERROR_NOT_ENOUGH_MEMORY

        int watchId = watchData->getId();

        _wid2WatchData[watchId] = watchData;

        watchDirectory(watchData);

        LeaveCriticalSection(&_cSection);

        return watchId;

    }

    catch (DWORD err)

    {

        error = err;

        LeaveCriticalSection(&_cSection);

        return 0;

    }

}

WatchData* Win32FSHook::find(int wd)

{

    WatchData* watchData = 0;

    EnterCriticalSection(&_cSection);

    map ::const_iterator it = _wid2WatchData.find(wd);

    if (it != _wid2WatchData.end())

    {

        watchData = it->second;

    }

    LeaveCriticalSection(&_cSection);

    return watchData;

}

DWORD WINAPI Win32FSHook::mainLoop(LPVOID lpParam)

{

    //  debug("mainLoop starts");

    Win32FSHook* _this = (Win32FSHook*)lpParam;

    HANDLE hPort = _this->_completionPort;

    DWORD dwNoOfBytes = 0;

    ULONG_PTR ulKey = 0;

    OVERLAPPED* pov = NULL;

    WCHAR name[4096];

    while (_this->_isRunning)

    {

        pov = NULL;

        BOOL fSuccess = GetQueuedCompletionStatus(

            hPort,         // Completion port handle

            &dwNoOfBytes,  // Bytes transferred

            &ulKey,

            &pov,          // OVERLAPPED structure

            INFINITE       // Notification time-out interval

        );

        if (fSuccess)

        {

            if (dwNoOfBytes == 0) continue; // happens when removing a watch some times.

            if (dwNoOfBytes == EXIT_SIGNAL)

                continue;

            if (dwNoOfBytes == DELETE_WD_SIGNAL)

            {

                WatchData* wd = (WatchData*)ulKey;

                delete wd;

                continue;

            }

            int wd = (int)ulKey;

            //      EnterCriticalSection(&_this->_cSection);

            WatchData* watchData = _this->find(wd);

            if (!watchData)

            {

                //          log("mainLoop : ignoring event for watch id %d, no longer in wid2WatchData map", wd);

                continue;

            }

            const char* buffer = watchData->getBuffer();

            //      char buffer[watchData->getBufferSize()];

            //      memcpy(buffer, watchData->getBuffer(), dwNoOfBytes);

            //          LeaveCriticalSection(&_this->_cSection);

            FILE_NOTIFY_INFORMATION* event;

            DWORD offset = 0;

            do

            {

                event = (FILE_NOTIFY_INFORMATION*)(buffer + offset);

                int action = event->Action;

                DWORD len = event->FileNameLength / sizeof(WCHAR);

                for (DWORD k = 0; k < len && k < (sizeof(name) - sizeof(WCHAR)) / sizeof(WCHAR); k++)

                {

                    name[k] = event->FileName[k];

                }

                name[len] = 0;

                _this->postEvent(new Event(watchData->getId(), action, watchData->getPath(), name));

                offset += event->NextEntryOffset;

            } while (event->NextEntryOffset != 0);

            int res = watchData->watchDirectory();

            if (res != 0)

            {

                //          log("Error watching dir %s : %d",watchData->getPath(), res);

            }

        }

        else

        {

            //      log("GetQueuedCompletionStatus returned an error");

        }

    }

    //  debug("mainLoop exits");

    return 0;

}

void Win32FSHook::watchDirectory(WatchData* wd)

{

    //  debug("Watching %ls", wd->getPath());

    int res = wd->watchDirectory();

    if (res != 0)

    {

        //      log("Error watching dir %ls : %d",wd->getPath(), res);

    }

}

void Win32FSHook::postEvent(Event* event)

{

    EnterCriticalSection(&_eventQueueLock);

    _eventQueue.push(event);

    LeaveCriticalSection(&_eventQueueLock);

    SetEvent(_eventQueueEvent);

}

DWORD WINAPI Win32FSHook::eventLoop(LPVOID lpParam)

{

    //  debug("eventLoop starts");

    Win32FSHook* _this = (Win32FSHook*)lpParam;

    queue local;

    while (1)

    {

        // quickly copy to local queue, minimizing the time holding the lock

        EnterCriticalSection(&_this->_eventQueueLock);

        while (_this->_eventQueue.size() > 0)

        {

            Event* e = _this->_eventQueue.front();

            local.push(e);

            _this->_eventQueue.pop();

        }

        LeaveCriticalSection(&_this->_eventQueueLock);

        while (local.size() > 0)

        {

            Event* e = local.front();

            local.pop();

            if (_this->_isRunning)

            {

                _this->_callback(e->_watchID, e->_action, e->_rootPath, e->_filePath);

            }

            delete e;

        }

        if (_this->_isRunning)

        {

            WaitForSingleObjectEx(_this->_eventQueueEvent, INFINITE, TRUE);

        }

        else

            break;

    }

    //  debug("eventLoop exits");

    return 0;

}

main.cpp:

#include

#include

#include

#include "Win32FSHook.h"

//因为文件钩子回调的参数是wchar_t *类型,为了让你的程序正常获取到参数的意思,要转成char *类型

//说明:待转换的字符串是wchar,返回值保存在m_char开辟的空间里

char* wchar2char(const wchar_t* wchar, char* m_char)

{

    int len = WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), NULL, 0, NULL, NULL);

    WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), m_char, len, NULL, NULL);

    m_char[len] = '';

    return m_char;

}

//因为添加文件钩子监听目标文件夹的时候,要用wchar_t *类型传参,为了方便,直接写个char *到wchar_t *的转换函数

//说明:待转换的字符串是cchar,返回值保存在m_wchar开辟的空间里

wchar_t* char2wchar(const char* cchar, wchar_t* m_wchar)

{

    int len = MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), NULL, 0);

    MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), m_wchar, len);

    m_wchar[len] = '';

    return m_wchar;

}

void win32FSCallback(int watchID, int action, const WCHAR* rootPath, const WCHAR* filePath)

{

    char tmp[256];    //windows系统文件名只需要256个字节就可以了

    char filename[256];

    strcpy(filename, wchar2char(rootPath, tmp));

    strcat(filename, wchar2char(filePath, tmp));  //把根目录和相对根目录的文件名拼起来就是完整的文件名了

    //std::cout<<"watchID: "<

    switch (action)

    {

    case 1:

    {

        std::cout << "创建:" << filename << std::endl;

        break;

    }

    case 2:

    {

        std::cout << "删除:" << filename << std::endl;

        break;

    }

    case 3:

    {

        std::cout << "复制:" << filename << std::endl;

        break;

    }

    case 4:  //在4时别急着换行,因为windows在回调了4之后,就会回调5,拼起来意思才完整

    {

        std::cout << "重命名原文件名:" << filename;

        break;

    }

    case 5:

    {

        std::cout << ",新文件名:" << filename << std::endl;

        break;

    }

    default:  //其他的一些操作,因为没有文档,我也不知道还有没有其他的action

    {

        std::cout << "操作代码'" << action << "':" << filename << std::endl;

    }

    }

}

int main()

{

    int watchID;

    Win32FSHook win32FSHook;

    win32FSHook.init(win32FSCallback);

    DWORD err;

    wchar_t path[256];

    watchID = win32FSHook.add_watch(char2wchar("C:\", path),

        1 | 2 | 4 | 8,

        true,

        err);

    if (err == 2)

    {

        std::cout << "该目录无法监听" << std::endl;

    }

    else

    {

        std::cout << "开始监听,按下回车结束监听" << std::endl;

        getchar();

        win32FSHook.remove_watch(watchID);

        std::cout << "结束监听,按下回车退出程序" << std::endl;

        getchar();

    }

    return 0;

}

结果:

 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/869511.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号