You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
6.9 KiB
C++

// XTPDirWatcher.cpp : implementation file
//
// This file is a part of the XTREME CONTROLS MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/XTPVC80Helpers.h" // Visual Studio 2005 helper functions
#include "../Defines.h"
#include "XTPShellPidl.h"
#include "XTPDirWatcher.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CXTPDirWatcher
CXTPDirWatcher::CXTPDirWatcher()
{
m_bWatchSubtree = FALSE;
m_bAutoDelete = TRUE;
m_dwMonitorEvents[0] = INVALID_HANDLE_VALUE;
m_dwMonitorEvents[1] = INVALID_HANDLE_VALUE;
m_dwMonitorEvents[2] = CreateEvent(NULL, TRUE, FALSE, 0); // Path was changed event.
m_dwMonitorEvents[3] = CreateEvent(NULL, TRUE, FALSE, 0); // Stop notifications event.
ZeroMemory(&m_tvid, sizeof(m_tvid));
}
CXTPDirWatcher::~CXTPDirWatcher()
{
CloseHandle(m_dwMonitorEvents[2]);
CloseHandle(m_dwMonitorEvents[3]);
}
void CXTPDirWatcher::StopNotifications()
{
SetEvent(m_dwMonitorEvents[3]);
WaitForSingleObject(m_hThread, INFINITE);
}
IMPLEMENT_DYNCREATE(CXTPDirWatcher, CWinThread)
BEGIN_MESSAGE_MAP(CXTPDirWatcher, CWinThread)
//{{AFX_MSG_MAP(CXTPDirWatcher)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CXTPDirWatcher::WaitPathChangedEvent()
{
DWORD dw = ::WaitForMultipleObjects(2,
&m_dwMonitorEvents[2], FALSE, INFINITE);
return dw != WAIT_OBJECT_0 + 1;
}
BOOL CXTPDirWatcher::MonitorNotifications()
{
BOOL bContinueThread = TRUE;
::ResetEvent(m_dwMonitorEvents[2]);
::ResetEvent(m_dwMonitorEvents[3]);
if (!IsPathValid(m_strFolderPath))
return WaitPathChangedEvent();
// Watch the directory for file creation and
// deletion.
m_dwMonitorEvents[0] = ::FindFirstChangeNotification(
m_strFolderPath, // directory to watch
m_bWatchSubtree, // monitor the subtree
FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes
if (m_dwMonitorEvents[0] == INVALID_HANDLE_VALUE)
return WaitPathChangedEvent();
// Watch the tree for directory creation and
// deletion.
m_dwMonitorEvents[1] = ::FindFirstChangeNotification(
m_strFolderPath, // directory to watch
m_bWatchSubtree, // monitor the subtree
FILE_NOTIFY_CHANGE_DIR_NAME); // watch dir. name changes
if (m_dwMonitorEvents[1] == INVALID_HANDLE_VALUE)
return WaitPathChangedEvent();
// Change notification is set. Now wait on both notification
// handles and refresh accordingly.
BOOL bConinueNotifications = TRUE;
while (bConinueNotifications)
{
// Wait for notification.
DWORD dwWaitStatus = ::WaitForMultipleObjects(_countof(m_dwMonitorEvents),
m_dwMonitorEvents, 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.
RefreshFolder();
if (!::FindNextChangeNotification(m_dwMonitorEvents[0]))
bConinueNotifications = FALSE;
if (!IsPathValid(m_strFolderPath))
bConinueNotifications = FALSE;
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();
if (!::FindNextChangeNotification(m_dwMonitorEvents[1]))
bConinueNotifications = FALSE;
if (!IsPathValid(m_strFolderPath))
bConinueNotifications = FALSE;
break;
case WAIT_OBJECT_0 + 2:
bContinueThread = TRUE;
bConinueNotifications = FALSE;
break;
case WAIT_OBJECT_0 + 3:
bContinueThread = FALSE;
bConinueNotifications = FALSE;
break;
}
}
// Close the file change notification handle and return.
::FindCloseChangeNotification (m_dwMonitorEvents[0]);
::FindCloseChangeNotification (m_dwMonitorEvents[1]);
m_dwMonitorEvents[0] = INVALID_HANDLE_VALUE;
m_dwMonitorEvents[1] = INVALID_HANDLE_VALUE;
return bContinueThread;
}
BOOL CXTPDirWatcher::InitInstance()
{
BOOL bContinueThread = TRUE;
while (bContinueThread)
{
bContinueThread = MonitorNotifications();
}
return FALSE;
}
BOOL CXTPDirWatcher::IsPathValid(LPCTSTR lpszFolderPath)
{
if (_tcslen(lpszFolderPath) == 0)
return FALSE;
if (!DIRECTORYEXISTS_S(lpszFolderPath))
return FALSE;
return TRUE;
}
BOOL CXTPDirWatcher::SetFolderPath(CWnd* pMainWnd, LPCTSTR lpszFolderPath, BOOL bWatchSubtree)
{
if (IsPathValid(lpszFolderPath))
{
if (GetFolderData(lpszFolderPath, m_tvid))
{
m_pMainWnd = pMainWnd;
m_strFolderPath = lpszFolderPath;
m_bWatchSubtree = bWatchSubtree;
SetEvent(m_dwMonitorEvents[2]); // Folder was changed event
return TRUE;
}
}
return FALSE;
}
BOOL CXTPDirWatcher::SetFolderData(CWnd* pMainWnd, XTP_TVITEMDATA* lpTVID)
{
if (!lpTVID)
return FALSE;
TCHAR szFolderPath[_MAX_PATH];
if (::SHGetPathFromIDList(lpTVID->lpifq, szFolderPath))
{
return SetFolderPath(pMainWnd, szFolderPath);
}
return FALSE;
}
BOOL CXTPDirWatcher::GetFolderData(LPCTSTR lpszFolderPath, XTP_TVITEMDATA& lpTVID)
{
LPITEMIDLIST pidl;
LPSHELLFOLDER pDesktopFolder;
OLECHAR szOleChar[MAX_PATH];
ULONG chEaten;
ULONG dwAttributes;
if (!IsPathValid(lpszFolderPath))
return FALSE;
// Get a pointer to the Desktop's IShellFolder interface.
if (SUCCEEDED(::SHGetDesktopFolder(&pDesktopFolder)))
{
// IShellFolder::ParseDisplayName requires the file name be in
// Unicode.
#if !defined(_UNICODE)
::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpszFolderPath, -1,
szOleChar, MAX_PATH);
#else
STRCPY_S(szOleChar, MAX_PATH, lpszFolderPath);
#endif
// Convert the path to an ITEMIDLIST.
if (SUCCEEDED(pDesktopFolder->ParseDisplayName(NULL, NULL, szOleChar,
&chEaten, &pidl, &dwAttributes)))
{
IShellFolder *psfMyFolder;
lpTVID.lpi = lpTVID.lpifq = pidl;
pDesktopFolder->BindToObject(lpTVID.lpifq, NULL,
IID_IShellFolder, (LPVOID*)&psfMyFolder);
lpTVID.lpsfParent = psfMyFolder;
pDesktopFolder->Release();
return TRUE;
}
pDesktopFolder->Release();
}
return FALSE;
}
void CXTPDirWatcher::RefreshFolder()
{
m_pMainWnd->SendMessage(WM_XTP_SHELL_NOTIFY,
SHN_XTP_REFRESHFOLDER, (LPARAM)&m_tvid);
}
void CXTPDirWatcher::RefreshTree()
{
m_pMainWnd->SendMessage(WM_XTP_SHELL_NOTIFY,
SHN_XTP_REFRESHTREE, (LPARAM)&m_tvid);
}