|
Hi,
I have a CXTShellListCtrl in a dialog box. When I close the dialog box and then navigate using the Windows Explorer to the directory that the CXTShellListCtrl was displaying and delete a file, or add a file my program will crash.
It crashes in CXTDirWatcher, there is a WaitForMultipleObject(...,INIFINT) in the InitInstance, since the dialog box is closed thread object is actually deleted, but it is still running, when the event hits, the thread crashes.
If I remember correctly I sent you guys a fix for this a year or so ago?
Do you guys have a fix for this?
If I remember correctly the fix is to change the thread into a worker thread instead of a gui thread.
// XTDirWatcher.cpp : implementation file // // This file is a part of the XTREME TOOLKIT MFC class library. // ©2004 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: // mailto:support@codejock.com - support@codejock.com // http://www.codejock.com - http://www.codejock.com // //////////////////////////////////////////////////////////// /////////////////
#include "stdafx.h" #include "XTDefines.h" #include "XTGlobal.h" #include "XTDirWatcher.h"
#include <io.h>
#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif
UINT DirWatcherThread(void *pParam); //////////////////////////////////////////////////////////// ///////////////// // CXTDirWatcher
CXTDirWatcher::CXTDirWatcher() : m_Exit(FALSE) , m_pThread(NULL) { // m_bAutoDelete = FALSE; }
CXTDirWatcher::~CXTDirWatcher() { m_Exit = TRUE; }
void CXTDirWatcher::StartMonitoring() { m_pThread = AfxBeginThread(DirWatcherThread,this); }
void CXTDirWatcher::SuspendThread() { ASSERT(m_pThread); m_pThread->SuspendThread(); }
void CXTDirWatcher::ResumeThread() { ASSERT(m_pThread); m_pThread->ResumeThread(); }
BOOL CXTDirWatcher::IsPathValid(LPCTSTR lpszFolderPath) { if (_tcslen(lpszFolderPath) == 0) return FALSE;
if (_taccess(lpszFolderPath, 0) == -1) return FALSE;
return TRUE; }
BOOL CXTDirWatcher::SetFolderPath(CWnd* pMainWnd, LPCTSTR lpszFolderPath) { if (IsPathValid(lpszFolderPath)) { if (GetFolderData(lpszFolderPath, m_tvid)) { m_pMainWnd = pMainWnd; m_strFolderPath = lpszFolderPath;
return TRUE; } }
return FALSE; }
BOOL CXTDirWatcher::SetFolderData(CWnd* pMainWnd, XT_TVITEMDATA* lpTVID) { if (!lpTVID) return FALSE;
TCHAR szFolderPath[_MAX_PATH]; if (::SHGetPathFromIDList(lpTVID->lpifq, szFolderPath)) { return SetFolderPath(pMainWnd, szFolderPath); }
return FALSE; }
BOOL CXTDirWatcher::GetFolderData(LPCTSTR lpszFolderPath, XT_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 ::_tcscpy( szOleChar, 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*)&psfMy Folder );
lpTVID.lpsfParent = psfMyFolder; pDesktopFolder->Release();
return TRUE; } pDesktopFolder->Release(); }
return FALSE; }
void CXTDirWatcher::RefreshFolder() { m_pMainWnd->SendMessage( XTWM_SHELL_NOTIFY, SHN_XT_REFRESHFOLDER, (LPARAM)&m_tvid ); }
void CXTDirWatcher::RefreshTree() { m_pMainWnd->SendMessage( XTWM_SHELL_NOTIFY, SHN_XT_REFRESHTREE, (LPARAM)&m_tvid ); }
UINT DirWatcherThread(void *pParam) { CXTDirWatcher *pWatcher = reinterpret_cast<CXTDirWatcher *>(pParam);
HANDLE m_dwChangeHandles[2]; // Change event handles.
m_dwChangeHandles[0] = INVALID_HANDLE_VALUE; m_dwChangeHandles[1] = INVALID_HANDLE_VALUE;
if (pWatcher->IsPathValid(pWatcher->GetFolderPath())) { // Watch the directory for file creation and // deletion. m_dwChangeHandles[0] = ::FindFirstChangeNotification( pWatcher->GetFolderPath(), & amp; nbsp; // directory to watch FALSE, // do not watch the subtree FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes if (m_dwChangeHandles[0] == INVALID_HANDLE_VALUE) return 0; // Watch the tree for directory creation and // deletion. m_dwChangeHandles[1] = ::FindFirstChangeNotification( pWatcher->GetFolderPath(), & amp; nbsp; // directory to watch TRUE, & amp; nbsp; & amp; nbsp; // watch the subtree FILE_NOTIFY_CHANGE_DIR_NAME); // watch dir. name changes if (m_dwChangeHandles[1] == INVALID_HANDLE_VALUE) return 0; // Change notification is set. Now wait on both notification // handles and refresh accordingly.
while (!pWatcher->MustExit()) { // Wait for notification. DWORD m_dwWaitStatus = ::WaitForMultipleObjects(_countof(m_dwChangeHandles), m_dwChangeHandles, FALSE, 10);
switch (m_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. pWatcher->RefreshFolder();
if (!::FindNextChangeNotification(m_dwChangeHandles[0])) return 0;
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. pWatcher->RefreshTree();
if (!FindNextChangeNotification(m_dwChangeHandles[1])) return 0;
break; } } } return 0; }
Ali Rafiee
|