目录监控源码分析2

接着上面的

DWORD dwChangeFilter = GetChangeFlags1();

进去看源码:


DWORD CDirWatcherDlg::GetChangeFlags1()
{


DWORD dwChangeNotifyFlags = 0UL;
FLAG_INFO arFlagInfo[]={
{IDC_CHECK_FILE_NAME1, FILE_NOTIFY_CHANGE_FILE_NAME},
{IDC_CHECK_DIR_NAME1, FILE_NOTIFY_CHANGE_DIR_NAME},
{IDC_CHECK_LAST_WRITE1, FILE_NOTIFY_CHANGE_LAST_WRITE},
{IDC_CHECK_LAST_ACCESS1, FILE_NOTIFY_CHANGE_LAST_ACCESS},
{IDC_CHECK_SIZE1, FILE_NOTIFY_CHANGE_SIZE},
{IDC_CHECK_ATTRIBUTES1, FILE_NOTIFY_CHANGE_ATTRIBUTES},
{IDC_CHECK_LAST_WRITE1, FILE_NOTIFY_CHANGE_LAST_WRITE},
{IDC_CHECK_LAST_ACCESS1, FILE_NOTIFY_CHANGE_LAST_ACCESS},
{IDC_CHECK_CREATION1, FILE_NOTIFY_CHANGE_CREATION},
{IDC_CHECK_SECURITY1, FILE_NOTIFY_CHANGE_SECURITY}
};


for(int i = 0; i < sizeof(arFlagInfo)/sizeof(arFlagInfo[0]); ++i)
{
dwChangeNotifyFlags |= (IsDlgButtonChecked(arFlagInfo[i].nCtrlId) == BST_CHECKED)? arFlagInfo[i].nFlag : 0;
}


return dwChangeNotifyFlags;
}

找到FLAG_INFO :

typedef struct {
UINT nCtrlId;
UINT nFlag;
} FLAG_INFO;


看样子就是遍历arFlagInfo[]  ,仔细一看是取那么多复选框的状态 然后返回

继续回到OnBtnMonitor()

BOOL bWatchSubDir = (BOOL)(IsDlgButtonChecked(IDC_CHECK_SUBDIR1) == BST_CHECKED);

这个选框看名字有特别的意思:是否遍历子目录  监控的时候如果选上这个就不是单单监控一个目录了,就是监控一个目录树

if( dwChangeFilter == 0 ){
MessageBox(_T("You must select one or more change filters in order to monitor a directory"));
return;
}

这句是让你总要选一个(除了"是否遍历子目录"选框   其他的至少选一个)


if( m_DirWatcher.IsWatchingDirectory( m_strDirectoryToMonitor) )
m_DirWatcher.UnwatchDirectory( m_strDirectoryToMonitor );

进去

BOOL CDirectoryChangeWatcher::IsWatchingDirectory(const CString & strDirName)const
/*********************************************
  Determines whether or not a directory is being watched


  be carefull that you have the same name path name, including the backslash
  as was used in the call to WatchDirectory().


 ie:
"C:\\Temp"
is different than
"C:\\Temp\\"
**********************************************/
{
CSingleLock lock( const_cast<CCriticalSection*>(&m_csDirWatchInfo), TRUE);
ASSERT( lock.IsLocked() );
int i;
if( GetDirWatchInfo(strDirName, i) )
return TRUE;
return FALSE;
}

弄一个互斥的锁 保证代码块的独占资源

进入GetDirWatchInfo() 他有3个重载   

CDirectoryChangeWatcher::CDirWatchInfo * CDirectoryChangeWatcher::GetDirWatchInfo(const CString & strDirName, int & ref_nIdx)const
{
if( strDirName.IsEmpty() )// can't be watching a directory if it's you don't pass in the name of it...
return FALSE;  //

CSingleLock lock(const_cast<CCriticalSection*>(&m_csDirWatchInfo), TRUE);


int max = m_DirectoriesToWatch.GetSize();
CDirWatchInfo * p = NULL;
for(int i = 0; i < max; ++i )
{
if( (p = m_DirectoriesToWatch[i]) != NULL
&& p->m_strDirName.CompareNoCase( strDirName ) == 0 )
{
ref_nIdx = i;
return p;
}
}

return NULL;//NOT FOUND
}

做防范检查之后加锁

在分析之前先了解一个类成员m_DirectoriesToWatch

CTypedPtrArray<CPtrArray, CDirWatchInfo*> m_DirectoriesToWatch; //holds info about the directories that we're watching.

这个大家百度一下  我理解的是一个指针数组   里面存的是CDirWatchInfo指针

贴两个网址大家慢慢去看

http://anony3721.blog.163.com/blog/static/5119742011420405729/

http://baike.baidu.com/link?url=RcSG6D-gofozP9XwUYLSZSEV-__qZSu1N0-_M0hPBEYFckTc8qaU1TKOVORunckehh0Olfga6lztTH8-9k_nGa

使用POSITION 类型来遍历m_DirectoriesToWatch

http://technet.microsoft.com/zh-cn/magazine/sdbk3yw6.aspx列出了m_DirectoriesToWatch的可用函数


继续看GetDirWatchInfo()

他就是查找这个目录是否加入了监控队列

如果找到就返回目录信息对象的指针  还返回他的位置


回到IsWatchingDirectory()

现在就很容易明白这个函数的意思了  判断指定目录是否已经加入了监控队列

继续返回 void CDirWatcherDlg::OnBtnMonitor() 

查看UnwatchDirectory

如果指定目录已经加入了监控队列 就干掉他

BOOL CDirectoryChangeWatcher::UnwatchDirectory(const CString & strDirToStopWatching)
/***************************************************************
FUNCTION: UnwatchDirectory(const CString & strDirToStopWatching -- if this directory is being watched, the watch is stopped


****************************************************************/
{
BOOL bRetVal = FALSE;






if( m_hCompPort != NULL )//The io completion port must be open
{
ASSERT( !strDirToStopWatching.IsEmpty() );

CSingleLock lock(&m_csDirWatchInfo, TRUE);
ASSERT( lock.IsLocked() );
int nIdx = -1;
CDirWatchInfo * pDirInfo = GetDirWatchInfo(strDirToStopWatching, nIdx);
if( pDirInfo != NULL
&& nIdx != -1 )
{


//stop watching this directory
VERIFY( pDirInfo->UnwatchDirectory( m_hCompPort ) );


//cleanup the object used to watch the directory
m_DirectoriesToWatch.SetAt(nIdx, NULL);
pDirInfo->DeleteSelf(this);
bRetVal = TRUE;
}
}


return bRetVal;
}

我们看到初始化时m_hCompPort被赋为空

就直接返回FALSE;

继续回到void CDirWatcherDlg::OnBtnMonitor() 

GetDlgItemText(IDC_EDIT_DIR_TO_MONITOR, m_strDirectoryToMonitor);
if( m_DirWatcher.GetFilterFlags() & CDirectoryChangeWatcher::FILTERS_DONT_USE_FILTERS )
{
m_strIncludeFilter1.Empty();
m_strExcludeFilter1.Empty();
}
else
{
GetDlgItemText(IDC_EDIT_INCLUDE_FILTER1, m_strIncludeFilter1);
GetDlgItemText(IDC_EDIT_EXCLUDE_FILTER1, m_strExcludeFilter1);


if( m_strIncludeFilter1 == _T("*.*") )
{
MessageBox(_T("For performance reasons, don't use *.* as the include filter. An empty string means the same thing."));
SetDlgItemText(IDC_EDIT_INCLUDE_FILTER1, _T(""));
m_strIncludeFilter1.Empty();
}
}

获取两个过滤edit的值   对于“包含过滤”来说  *.*和空表示一样的意思

之后做最后一件事:

DWORD dwWatch = 0;
if( ERROR_SUCCESS != (dwWatch = m_DirWatcher.WatchDirectory(m_strDirectoryToMonitor, 
dwChangeFilter,
&m_DirChangeHandler,
bWatchSubDir,
m_strIncludeFilter1,
m_strExcludeFilter1)) )
{
MessageBox(_T("Failed to start watch:\n") + GetLastErrorMessageString( dwWatch ) );
}

其中看看m_DirChangeHandler 声明:CDirectoryChangeHandler_ListBox m_DirChangeHandler;

class CDirectoryChangeHandler_ListBox : public CDirectoryChangeHandler

这是监控目录监控之后的处理


进入WatchDirectory

ASSERT( dwChangesToWatchFor != 0);


if( strDirToWatch.IsEmpty()
||  dwChangesToWatchFor == 0 
||  pChangeHandler == NULL )
{
TRACE(_T("ERROR: You've passed invalid parameters to CDirectoryChangeWatcher::WatchDirectory()\n"));
::SetLastError(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}


这是参数检查

//double check that it's really a directory
if( !IsDirectory( strDirToWatch ) )
{
TRACE(_T("ERROR: CDirectoryChangeWatcher::WatchDirectory() -- %s is not a directory!\n"), strDirToWatch);
::SetLastError(ERROR_BAD_PATHNAME);
return ERROR_BAD_PATHNAME;
}

确定指定路径是个目录

if( IsWatchingDirectory( strDirToWatch) )
{
VERIFY( 
UnwatchDirectory( strDirToWatch ) 
);
}

如果已经监控了 就干掉  

CPrivilegeEnabler::Instance();  跟进去

发现这个类似单例模式  写法新奇  确实实现了单例功能

这个单例类初始化的时候做了一件事

BOOL EnablePrivilege(LPCTSTR pszPrivName, BOOL fEnable /*= TRUE*/) 
//
// I think this code is from a Jeffrey Richter book...
//
// Enables user priviledges to be set for this process.
//
// Process needs to have access to certain priviledges in order
// to use the ReadDirectoryChangesW() API.  See documentation.
{    
BOOL fOk = FALSE;    
// Assume function fails    
HANDLE hToken;    
// Try to open this process's access token    
if (OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES, &hToken))
{        
// privilege        
TOKEN_PRIVILEGES tp = { 1 };        


if( LookupPrivilegeValue(NULL, pszPrivName,  &tp.Privileges[0].Luid) )
{
tp.Privileges[0].Attributes = fEnable ?  SE_PRIVILEGE_ENABLED : 0;


AdjustTokenPrivileges(hToken, FALSE, &tp,      
sizeof(tp), NULL, NULL);


fOk = (GetLastError() == ERROR_SUCCESS);
}
CloseHandle(hToken);
}
return(fOk);
}

先了解一下

SE_BACKUP_NAME 备份文件和目录

SE_RESTORE_NAME 还原文件和目录

SE_CHANGE_NOTIFY_NAME 跳过遍历检查,允许用户来回移动目录

EnablePrivilege()

OpenProcessToken函数用来打开与进程相关联的访问令牌

LookupPrivilegeValue函数查看系统权限的特权值,返回信息到一个LUID结构体里。

djustTokenPrivileges这个函数启用或禁止 指定访问令牌的特权。

这三个函数加在一起就是干提升权限的


那这样的话 我们提升了3个权限

回到CDirectoryChangeWatcher.WatchDirectory ()

CreateFile打开目录

重点来了

创建一个监控信息对象 我们进去看看

CDirWatchInfo * pDirInfo = new CDirWatchInfo( hDir, strDirToWatch, pChangeHandler, dwChangesToWatchFor, bWatchSubDirs, m_bAppHasGUI, szIncludeFilter, szExcludeFilter, m_dwFilterFlags);
if( !pDirInfo )
{
TRACE(_T("WARNING: Couldn't allocate a new CDirWatchInfo() object --- File: %s Line: %d\n"), _T( __FILE__ ), __LINE__);
CloseHandle( hDir );
::SetLastError(ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}

如果监控信息对象创建失败就返回

之后我们要进入监控信息对象的构造函数 开始了解解决溢出的问题







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值