现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

监视文件夹(目录)中的文件改动的三种方法

2014-01-10 22:23 工业·编程 ⁄ 共 5167字 ⁄ 字号 暂无评论

方法一:

// test1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];

// Watch the C:/WINDOWS directory for file creation and
// deletion.

dwChangeHandles[0] = FindFirstChangeNotification(
  _T("C://WINDOWS"),                 // directory to watch
  FALSE,                         // do not watch the subtree
  FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes

if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
  ExitProcess(GetLastError());

// Watch the C:/ subtree for directory creation and
// deletion.

dwChangeHandles[1] = FindFirstChangeNotification(
  _T("C://"),                        // directory to watch
  TRUE,                          // watch the subtree
  FILE_NOTIFY_CHANGE_DIR_NAME);  // watch dir. name changes

if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
  ExitProcess(GetLastError());

// Change notification is set. Now wait on both notification
// handles and refresh accordingly.

while (TRUE)
{

  // Wait for notification.

  dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
   FALSE, INFINITE);

  switch (dwWaitStatus)
  {
  case WAIT_OBJECT_0:

   // A file was created or deleted in C:/WINDOWS.
   // Refresh this directory and restart the
   // change notification. RefreshDirectory is an
   // application-defined function.

   //RefreshDirectory("C://WINDOWS") ;
   ::MessageBox(NULL, _T("C:/WINDOWS 目录中文件名有改变"), _T(""), MB_OK);
    if ( FindNextChangeNotification( dwChangeHandles[0]) == FALSE )
     ExitProcess(GetLastError());
   break;

  case WAIT_OBJECT_0 + 1:

   // A directory was created or deleted in C:/.
   // Refresh the directory tree and restart the
   // change notification. RefreshTree is an
   // application-defined function.

   //RefreshTree("C://");
   ::MessageBox(NULL, _T("C:/ 目录中文件有改变"), _T(""), MB_OK);

   if (FindNextChangeNotification(
    dwChangeHandles[1]) == FALSE)
    ExitProcess(GetLastError());
   break;

  default:
   ExitProcess(GetLastError());
  }
}

return 0;
}

方法二:

=================================================================
通过 未公开API SHChangeNotifyRegister 实现
=================================================================
Windows 内部有两个未公开的函数(注:在最新的MSDN中,已经公开了这两个函数),分别叫做SHChangeNotifyRegister和 SHChangeNotifyDeregister,可以实现以上的功能。这两个函数位于Shell32.dll中,是用序号方式导出的。这就是为什么我们用VC自带的Depends工具察看Shell32.dll时,找不到这两个函数的原因。SHChangeNotifyRegister的导出序号是 2;而SHChangeNotifyDeregister的导出序号是4。
SHChangeNotifyRegister可以把指定的窗口添加到系统的消息监视链中,这样窗口就能接收到来自文件系统或者Shell的通知了。而对应的另一个函数,SHChangeNotifyDeregister,则用来取消监视钩挂。SHChangeNotifyRegister的原型和相关参数如下:
ULONG SHChangeNotifyRegister
(       
HWND hwnd,
    int  fSources,
    LONG fEvents,
    UINT    wMsg,
    Int cEntries,
    SHChangeNotifyEntry *pfsne
);
其中:
hwnd
将要接收改变或通知消息的窗口的句柄。
fSource
指示接收消息的事件类型,将是下列值的一个或多个(注:这些标志没有被包括在任何头文件中,使用者须在自己的程序中加以定义或者直接使用其对应的数值)
SHCNRF_InterruptLevel
0x0001。接收来自文件系统的中断级别通知消息。
SHCNRF_ShellLevel
0x0002。接收来自Shell的Shell级别通知消息。
SHCNRF_RecursiveInterrupt
0x1000。接收目录下所有子目录的中断事件。此标志必须和SHCNRF_InterruptLevel 标志合在一起使用。当使用该标志时,必须同时设置对应的SHChangeNotifyEntry结构体中的fRecursive成员为TRUE(此结构体由函数的最后一个参数pfsne指向),这样通知消息在目录树上是递归的。
SHCNRF_NewDelivery
0x8000。接收到的消息使用共享内存。必须先调用SHChangeNotification_Lock,然后才能存取实际的数据,完成后调用SHChangeNotification_Unlock函数释放内存。
fEvents
要捕捉的事件,其所有可能的值请参见MSDN中关于SHChangeNotify函数的注解。
wMsg
产生对应的事件后,发往窗口的消息。
cEntries
pfsne指向的数组的成员的个数。
pfsne
SHChangeNotifyEntry 结构体数组的起始指针。此结构体承载通知消息,其成员个数必须设置成1,否则SHChangeNotifyRegister或者 SHChangeNotifyDeregister将不能正常工作(但是据我试验,如果cEntries设为大于1的值,依然可以注册成功,不知何故)。
如果函数调用成功,则返回一个整型注册标志号,否则将返回0。同时系统就会将hwnd指定的窗口加入到操作监视链中,当有文件操作发生时,系统会向hwnd标识的窗口发送wMsg指定的消息,我们只要在程序中加入对该消息的处理函数就可以实现对系统操作的监视了。
如果要退出程序监视,就要调用另外一个未公开得函数SHChangeNotifyDeregister来取消程序监视。该函数的原型如下:
BOOL SHChangeNotifyDeregister(ULONG ulID);
其中ulID指定了要注销的监视注册标志号,如果卸载成功,返回TRUE,否则返回FALSE

方法三:

通过 ReadDirectoryChangesW 实现

bool Monitor()
{
    HANDLE hFile  =  CreateFile(
        "c://",
        GENERIC_READ|GENERIC_WRITE,
        FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS,
        NULL
        );
    if(  INVALID_HANDLE_VALUE  ==  hFile  )  return  false;
    char  buf[  2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH)  ];
    FILE_NOTIFY_INFORMATION*  pNotify=(FILE_NOTIFY_INFORMATION  *)buf;
    DWORD  BytesReturned;
    while(true)
    {
        if(  ReadDirectoryChangesW(  hFile,
            pNotify,
            sizeof(buf),
            true,
            FILE_NOTIFY_CHANGE_FILE_NAME|
            FILE_NOTIFY_CHANGE_DIR_NAME|
            FILE_NOTIFY_CHANGE_ATTRIBUTES|
            FILE_NOTIFY_CHANGE_SIZE|
            FILE_NOTIFY_CHANGE_LAST_WRITE|
            FILE_NOTIFY_CHANGE_LAST_ACCESS|
            FILE_NOTIFY_CHANGE_CREATION|
            FILE_NOTIFY_CHANGE_SECURITY,
            &BytesReturned,
            NULL,
            NULL  )  )
        {
            char  tmp[MAX_PATH],  str1[MAX_PATH],  str2[MAX_PATH];
            memset(  tmp,  0,  sizeof(tmp)  );
            WideCharToMultiByte(  CP_ACP,0,pNotify->FileName,pNotify->FileNameLength/2,tmp,99,NULL,NULL  );
            strcpy(  str1,  tmp  );
            if(  0  !=  pNotify->NextEntryOffset  )
            {
                PFILE_NOTIFY_INFORMATION  p  =  (PFILE_NOTIFY_INFORMATION)((char*)pNotify+pNotify->NextEntryOffset);
                memset(  tmp,  0,  sizeof(tmp)  );
                WideCharToMultiByte(  CP_ACP,0,p->FileName,p->FileNameLength/2,tmp,99,NULL,NULL  );
                strcpy(  str2,  tmp  );
            }
            // your process
        }
        else
        {
            break;
        }
    }
    return true;
}

给我留言

留言无头像?