Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Resource ID Organiser Add-In for Visual C++ 5.0/6.0/.NET

, 10 Jan 2005
An application/add-in to organise and renumber resource symbol IDs
resorg103.zip
resorg104.zip
resorgaddinsetup.zip
resorgaddin_executables.zip
resorgnetaddinsetup.zip
resorgnetaddin_executables.zip
resorgnet_executables.zip
ResOrgNET_executables
CJ609LibVc7.dll
NGLib103Vc7.dll
QHTMLight.dll
ResOrg.cnt
resorg.fts
ResOrg.hlp
ResOrgNETAddIn.dll
ResOrgNETAddInToolWindows.ocx
ResOrgNETCore.dll
resorg_demo.zip
resorg_executables.zip
resorg_src.zip
BXFileDialog
BXFileDialog.dsp
Lib
Release
Res
bitmap2.bmp
FileOpen.bmp
filesave.bmp
CJLibrary
CJLibrary
CJLibrary.def
CJLibrary.dsp
CJLibrary.dsw
CJLibrarydep.jpg
CJLibraryStatic.dsp
Debug_Unicode
Release
Release_Unicode
res
Include
res
btn_arro.bmp
btn_explorer.bmp
button_images.bmp
cj_logo.bmp
dragging.cur
handcur.cur
headerba.bmp
hsplitba.cur
icr_hand.cur
nodraggi.cur
PushPin.bmp
Toolbar.bmp
vsplitba.cur
Lib
NGLibrary
Bin
NGLibrary.def
NGLibrary.dsp
NGLibrary.dsw
Release
Res
Drives.bmp
Release
ResOrgAddIn
Release
Res
HtmlDoc.ico
ResOrg.ico
ResOrgDoc.ico
TBarLrge.bmp
TBarMedm.bmp
Toolbar.bmp
WorkspaceTabs.bmp
ResOrgAddIn.def
ResOrgAddIn.dsp
ResOrgAddIn.odl
ResOrgAddIn_Res.hm
ResOrgApp
Lint
Release
Res
HtmlDoc.ico
MAINFRAM.BMP
ResOrg.ico
ResOrgDoc.ico
TBarLrge.bmp
TBarMedm.bmp
Toolbar.bmp
workspace.ico
WorkspaceTabs.bmp
ResOrgApp.dsp
ResOrgApp_Res.hm
ResOrgApp_Res.resorg
ResOrgCore
Lint
Release
Res
Anna.bmp
BuildOptions.ico
ComCtl Version Prompt.rtf
File Reload Warning Ex.rtf
File Reload Warning.rtf
Global Next Symbol Value Warning Prompt.rtf
information.ico
Invalid Symbol Name.rtf
Mailing List Prompt.rtf
Next Symbol Value Warning Prompt.rtf
project context menu.bmp
project.ico
RenumWiz Completion.rtf
Report.ico
ResOrg Logo.bmp
ResOrg Updated.rtf
ResOrg.ico
resource file.ico
riverblade_logo.bmp
solution.ico
Symbol Delete Warning.rtf
Symbol Name Warning.rtf
Symbol Rename Warning.rtf
SymbolFile.ico
Symbols Delete Warning.rtf
sym_binary.ico
sym_bitmap.ico
sym_command.ico
sym_control.ico
sym_dialog.ico
sym_icon.ico
sym_menu.ico
sym_prompt.ico
sym_resource.ico
sym_string.ico
Toolbar.bmp
VcAddIn.ico
VersionCheck.ico
warning.ico
WizardHeader256.bmp
WizardWatermark256.bmp
ResOrgCore.def
ResOrgCore.dsp
ResOrgCore_Res.hm
ResOrgCore_Res.resorg
Xml
ProblemSymbolReportHtml.xsl
SymbolsReportHtml.xsl
ResOrgNETAddIn
AddIn.def
Release
Res
AddIn.rgs
HtmlDoc.ico
ResOrg.ico
ResOrgDoc.ico
Toolbar.bmp
WorkspaceTabs.bmp
ResOrgNETAddInSetup
Banner.jpg
Intro screen.jpg
Licence.rtf
ReadMe.rtf
Release
ResOrg.ico
ResOrgNETAddInSetup.vdproj
ResOrgNETAddInToolWindows
Release
Res
Edit.ico
Properties.ico
Renumber.ico
ResOrgNETAddInToolWindows.ico
ResOrgNETAddInToolWindowsCtrl.bmp
ResOrgNETAddInToolWindows.def
SatelliteDll
Release
res
AboutBoxCmd.bmp
OpenResOrgCmd.bmp
OptionsCmd.bmp
ViewMainToolWinCmd.bmp
//***********************************************************************
//
//  NGDriveView.cpp
//
//***********************************************************************

#include "stdafx.h"
#include <afxwin.h>
#include <afxcview.h>
#include <afxcoll.h>
#include <afxmt.h>
#include "NGLibrary_Res.h"						// Resource symbol definitions
#include "NGDriveView.h"

// Image list indexes
#define ILI_HARD_DISK       0
#define ILI_FLOPPY          1
#define ILI_CD_ROM          2
#define ILI_NET_DRIVE       3
#define ILI_RAM_DRIVE       4
#define ILI_CLOSED_FOLDER   5
#define ILI_OPEN_FOLDER     6

IMPLEMENT_DYNCREATE (CNGDriveView, CTreeView)

BEGIN_MESSAGE_MAP (CNGDriveView, CTreeView)
    ON_WM_DESTROY ()
    ON_NOTIFY_REFLECT (TVN_ITEMEXPANDING, OnItemExpanding)
    ON_NOTIFY_REFLECT (TVN_SELCHANGED, OnSelChanged)
    ON_MESSAGE (WM_USER, OnDriveContentsChanged)
END_MESSAGE_MAP ()

/////////////////////////////////////////////////////////////////////////
// Class constructor

CNGDriveView::CNGDriveView () : m_event (FALSE, TRUE)
{
    m_nThreadCount = 0;
}

/////////////////////////////////////////////////////////////////////////
// Overridables

BOOL CNGDriveView::PreCreateWindow (CREATESTRUCT& cs)
{
    if (!CTreeView::PreCreateWindow (cs))
        return FALSE;

    cs.style |= TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS;
    return TRUE;
}

void CNGDriveView::OnInitialUpdate ()
{
    CTreeView::OnInitialUpdate ();
    m_imglDrives.Create (IDR_DRIVEIMAGES, 16, 1, RGB (255, 0, 255));
    GetTreeCtrl ().SetImageList (&m_imglDrives, TVSIL_NORMAL);
    InitTree ();
}

void CNGDriveView::OnSelectionChanged (CString& strPathName)
{
    //
    // NOTE: Override this function in a derived class to respond
    // to selection changes differently. The default implementation
    // calls UpdateAllViews to update other views of the document.
    //
    GetDocument ()->UpdateAllViews (this,
        (LPARAM) (LPCTSTR) strPathName);
}

/////////////////////////////////////////////////////////////////////////
// Message handlers

void CNGDriveView::OnDestroy ()
{
    // Kill all running file change notification threads.
    if (m_nThreadCount) {
        m_event.SetEvent ();
        ::WaitForMultipleObjects (m_nThreadCount, m_hThreads, TRUE,
            INFINITE);
        m_nThreadCount = 0;
    }

    // Call the base class's OnDestroy handler.
    CTreeView::OnDestroy ();
}

void CNGDriveView::OnItemExpanding (NMHDR* pnmh, LRESULT* pResult)
{
    NM_TREEVIEW* pnmtv = (NM_TREEVIEW*) pnmh;
    HTREEITEM hItem = pnmtv->itemNew.hItem;
    CString strPathName = GetPathFromItem (hItem);
    *pResult = FALSE;

    // Reset the drive node if the drive is empty or the media changed.
    if (!IsMediaValid (strPathName)) {
        HTREEITEM hRoot = GetDriveNode (hItem);
        GetTreeCtrl ().Expand (hRoot, TVE_COLLAPSE);
        DeleteChildren (hRoot);
        AddDummyNode (hRoot);
        *pResult = TRUE;
        return;
    }

    // Delete the item if strPathName no longer specifies a valid path.
    if (!IsPathValid (strPathName)) {
        GetTreeCtrl ().DeleteItem (hItem);
        *pResult = TRUE;
        return;
    }

    // If the item is expanding, delete the dummy item attached to it
    // and add folder items. If the item is collapsing instead, delete
    // its folder items and add a dummy item if appropriate.
    if (pnmtv->action == TVE_EXPAND) {
        DeleteChildren (hItem);
        if (!AddDirectoryNodes (hItem, strPathName))
            *pResult = TRUE;
    }
    else {
        DeleteChildren (hItem);
        if (IsDriveNode (hItem))
            AddDummyNode (hItem);
        else
            SetButtonState (hItem, strPathName);
    }
}

void CNGDriveView::OnSelChanged (NMHDR* pnmh, LRESULT* /*pResult*/)
{
    HTREEITEM hItem = ((NM_TREEVIEW*) pnmh)->itemNew.hItem;
    CString strPathName = GetPathFromItem (hItem);

    // Reset the drive node if the drive is empty or the media changed.
    if (!IsMediaValid (strPathName)) {
        HTREEITEM hRoot = GetDriveNode (hItem);
        GetTreeCtrl ().Expand (hRoot, TVE_COLLAPSE);
        DeleteChildren (hRoot);
        AddDummyNode (hRoot);
        return;
    }

    // Delete the item if strPathName no longer specifies a valid path.
    if (!IsPathValid (strPathName)) {
        GetTreeCtrl ().DeleteItem (hItem);
        return;
    }

    // Update the item's button state if the item is not expanded.
    if (!(GetTreeCtrl ().GetItemState (hItem, TVIS_EXPANDED) &
        TVIS_EXPANDED) || !GetTreeCtrl ().ItemHasChildren (hItem))
        UpdateButtonState (hItem, strPathName);

    // Call the view's virtual OnSelectionChanged function.
    OnSelectionChanged (strPathName);
}

LONG CNGDriveView::OnDriveContentsChanged (UINT wParam, LONG /*lParam*/)
{
    RefreshDrive ((UINT) wParam);
    return 0;
}

/////////////////////////////////////////////////////////////////////////
// Public member functions

void CNGDriveView::RefreshDrive (UINT nDrive)
{
    // Find the HTREEITEM that corresponds to the target drive.
    CString strDrive = "?:\\";
    strDrive.SetAt (0, (TCHAR)(0x41 + nDrive));

    HTREEITEM hItem =
        FindItem (GetTreeCtrl ().GetNextItem (NULL, TVGN_ROOT),
        strDrive);

    if (hItem == NULL)
        return;

    // Reset the drive node if the drive is empty or the media changed.
    if (!IsMediaValid (strDrive)) {
        GetTreeCtrl ().Expand (hItem, TVE_COLLAPSE);
        DeleteChildren (hItem);
        AddDummyNode (hItem);
        return;
    }

    // Save the current drive and directory.
    char szHome[MAX_PATH];
    ::GetCurrentDirectory (sizeof (szHome), szHome);

    // Change to the root directory of the target drive.
    if (!::SetCurrentDirectory ((LPCTSTR) strDrive))
        return; // Invalid drive specification

    // Refresh the drive node and all displayed subfolders.
    if (hItem != NULL)
        RefreshDirectory (hItem);

    // Return to the original drive and directory.
    ::SetCurrentDirectory (szHome);
}

CString CNGDriveView::GetPathFromItem (HTREEITEM hItem)
{
    CString strPathName;
    while (hItem != NULL) {
        CString string = GetTreeCtrl ().GetItemText (hItem);
        if ((string.Right (1) != "\\") && !strPathName.IsEmpty ())
            string += "\\";
        strPathName = string + strPathName;
        hItem = GetTreeCtrl ().GetParentItem (hItem);
    }
    return strPathName;
}

BOOL CNGDriveView::ExpandPath (LPCTSTR pszPath, BOOL bSelectItem)
{
    if (::lstrlen (pszPath) < 3)
        return FALSE;

    // Begin by finding the corresponding drive node.
    CString strPathName = pszPath;
    CString strDrive = strPathName.Left (3);

    HTREEITEM hItem =
        FindItem (GetTreeCtrl ().GetNextItem (NULL, TVGN_ROOT),
        strDrive);

    if (hItem == NULL)
        return FALSE; // Invalid drive specification

    strPathName = strPathName.Right (strPathName.GetLength () - 3);

    // Now bore down through the directory structure searching for the
    // item that corresponds to the final directory name in pszPath.
    while (strPathName.GetLength () > 0) {
        GetTreeCtrl ().Expand (hItem, TVE_EXPAND);
        hItem = GetTreeCtrl ().GetChildItem (hItem);
        if (hItem == NULL)
            return FALSE;

#if 1	// Eliminate compiler warning
		// AJM 15/11/99
        int nIndex = strPathName.Find ('\\');
		CString sFind = strPathName;
		if (nIndex != -1)
		{
	        sFind = strPathName.Left(nIndex);
		}
        hItem = FindItem(hItem, sFind); 
#else
			hItem = FindItem (hItem, nIndex == -1 ? strPathName :
            strPathName.Left (nIndex));
#endif
        if (hItem == NULL)
            return FALSE; // Invalid path name

        if (nIndex == -1)
            strPathName.Empty ();
        else
            strPathName = strPathName.Right (strPathName.GetLength () -
                nIndex - 1);
    }

    GetTreeCtrl ().Expand (hItem, TVE_EXPAND);
    if (bSelectItem)
        GetTreeCtrl ().Select (hItem, TVGN_CARET);
    return TRUE;
}

/////////////////////////////////////////////////////////////////////////
// Protected helper functions

UINT CNGDriveView::InitTree ()
{
    int nPos = 0;
    UINT nCount = 0;
    CString strDrive = "?:\\";

    DWORD dwDriveList = ::GetLogicalDrives ();

    while (dwDriveList) {
        if (dwDriveList & 1) {
            strDrive.SetAt (0, (TCHAR)(0x41 + nPos));
            if (AddDriveNode (strDrive))
                nCount++;
        }
        dwDriveList >>= 1;
        nPos++;
    }
    return nCount;
}

BOOL CNGDriveView::AddDriveNode (CString& strDrive)
{
    HTREEITEM hItem;

    UINT nType = ::GetDriveType ((LPCTSTR) strDrive);
    UINT nDrive = (UINT) strDrive[0] - 0x41;

    switch (nType) {

    case DRIVE_REMOVABLE:
        hItem = GetTreeCtrl ().InsertItem (strDrive, ILI_FLOPPY,
            ILI_FLOPPY);
        AddDummyNode (hItem);
        m_dwMediaID[nDrive] = GetSerialNumber (strDrive);
        break;

    case DRIVE_FIXED:
        hItem = GetTreeCtrl ().InsertItem (strDrive, ILI_HARD_DISK,
            ILI_HARD_DISK);
        SetButtonState (hItem, strDrive);
        CreateMonitoringThread (strDrive);
        break;

    case DRIVE_REMOTE:
        hItem = GetTreeCtrl ().InsertItem (strDrive, ILI_NET_DRIVE,
            ILI_NET_DRIVE);
        SetButtonState (hItem, strDrive);
        CreateMonitoringThread (strDrive);
        break;

    case DRIVE_CDROM:
        hItem = GetTreeCtrl ().InsertItem (strDrive, ILI_CD_ROM,
            ILI_CD_ROM);
        AddDummyNode (hItem);
        m_dwMediaID[nDrive] = GetSerialNumber (strDrive);
        break;

    case DRIVE_RAMDISK:
        hItem = GetTreeCtrl ().InsertItem (strDrive, ILI_RAM_DRIVE,
            ILI_RAM_DRIVE);
        SetButtonState (hItem, strDrive);
        CreateMonitoringThread (strDrive);
        break;

    default:
        return FALSE;
    }

    return TRUE;
}

UINT CNGDriveView::AddDirectoryNodes (HTREEITEM hItem, CString& strPathName)
{
    HANDLE hFind;
    WIN32_FIND_DATA fd;

    UINT nCount = 0;

    CString strFileSpec = strPathName;
    if (strFileSpec.Right (1) != "\\")
        strFileSpec += "\\";
    strFileSpec += "*.*";

    if ((hFind = ::FindFirstFile ((LPCTSTR) strFileSpec, &fd)) ==
        INVALID_HANDLE_VALUE) {
        if (IsDriveNode (hItem))
            AddDummyNode (hItem);
        return 0;
    }

    do {
        if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            CString strFileName = (LPCTSTR) &fd.cFileName;
            if ((strFileName != ".") && (strFileName != "..")) {
                HTREEITEM hChild =
                    GetTreeCtrl ().InsertItem ((LPCTSTR) &fd.cFileName,
                    ILI_CLOSED_FOLDER, ILI_OPEN_FOLDER, hItem, TVI_SORT);

                CString strNewPathName = strPathName;
                if (strNewPathName.Right (1) != "\\")
                    strNewPathName += "\\";

                strNewPathName += (LPCTSTR) &fd.cFileName;
                SetButtonState (hChild, strNewPathName);
                nCount++;
            }
        }
    } while (::FindNextFile (hFind, &fd));

    ::FindClose (hFind);
    return nCount;
}

void CNGDriveView::SetButtonState (HTREEITEM hItem, CString& strPathName)
{
    if (HasSubdirectory (strPathName))
        AddDummyNode (hItem);
}

void CNGDriveView::UpdateButtonState (HTREEITEM hItem, CString& strPathName)
{
    if (HasSubdirectory (strPathName)) {
        if (!GetTreeCtrl ().ItemHasChildren (hItem)) {
            AddDummyNode (hItem);
            Invalidate ();
        }
    }
    else {
        if (GetTreeCtrl ().ItemHasChildren (hItem))
            DeleteChildren (hItem);
    }
}

BOOL CNGDriveView::HasSubdirectory (CString& strPathName)
{
    HANDLE hFind;
    WIN32_FIND_DATA fd;
    BOOL bResult = FALSE;

    CString strFileSpec = strPathName;
    if (strFileSpec.Right (1) != "\\")
        strFileSpec += "\\";
    strFileSpec += "*.*";

    if ((hFind = ::FindFirstFile ((LPCTSTR) strFileSpec, &fd)) !=
        INVALID_HANDLE_VALUE) {
        do {
            if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                CString strFileName = (LPCTSTR) &fd.cFileName;
                if ((strFileName != ".") && (strFileName != ".."))
                    bResult = TRUE;
            }
        } while (::FindNextFile (hFind, &fd) && !bResult);
        ::FindClose (hFind);
    }

    return bResult;
}

BOOL CNGDriveView::IsDriveNode (HTREEITEM hItem)
{
    return (GetTreeCtrl ().GetParentItem (hItem) == NULL) ? TRUE : FALSE;
}

void CNGDriveView::AddDummyNode (HTREEITEM hItem)
{
    GetTreeCtrl ().InsertItem ("", 0, 0, hItem);
}

HTREEITEM CNGDriveView::FindItem (HTREEITEM hItem, CString& strTarget)
{
    while (hItem != NULL) {
        if (GetTreeCtrl ().GetItemText (hItem) == strTarget)
            break;
        hItem = GetTreeCtrl ().GetNextSiblingItem (hItem);
    }
    return hItem;
}

UINT CNGDriveView::DeleteChildren (HTREEITEM hItem)
{
    UINT nCount = 0;
    HTREEITEM hChild = GetTreeCtrl ().GetChildItem (hItem);

    while (hChild != NULL) {
        HTREEITEM hNextItem = GetTreeCtrl ().GetNextSiblingItem (hChild);
        GetTreeCtrl ().DeleteItem (hChild);
        hChild = hNextItem;
        nCount++;
    }
    return nCount;
}

HTREEITEM CNGDriveView::GetDriveNode (HTREEITEM hItem)
{
    HTREEITEM hParent;

    do {
        hParent = GetTreeCtrl ().GetParentItem (hItem);
        if (hParent != NULL)
            hItem = hParent;
    } while (hParent != NULL);
    return hItem;
}

DWORD CNGDriveView::GetSerialNumber (CString& strDrive)
{
    DWORD dwSerialNumber;
    if (!::GetVolumeInformation ((LPCTSTR) strDrive, NULL, 0,
        &dwSerialNumber, NULL, NULL, NULL, 0))
        dwSerialNumber = 0xFFFFFFFF;
    return dwSerialNumber;
}

BOOL CNGDriveView::IsMediaValid (CString& strPathName)
{
    // Return TRUE if the drive doesn't support removable media.
    UINT nDriveType = GetDriveType ((LPCTSTR) strPathName);
    if ((nDriveType != DRIVE_REMOVABLE) && (nDriveType != DRIVE_CDROM))
        return TRUE;

    // Return FALSE if the drive is empty (::GetVolumeInformation fails).
    DWORD dwSerialNumber;
    CString strDrive = strPathName.Left (3);
    UINT nDrive = (UINT) strDrive[0] - 0x41;

    if (!::GetVolumeInformation ((LPCTSTR) strDrive, NULL, 0,
        &dwSerialNumber, NULL, NULL, NULL, 0)) {
        m_dwMediaID[nDrive] = 0xFFFFFFFF;
        return FALSE;
    }

    // Also return FALSE if the disk's serial number has changed.
    if ((m_dwMediaID[nDrive] != dwSerialNumber) &&
        (m_dwMediaID[nDrive] != 0xFFFFFFFF)) {
        m_dwMediaID[nDrive] = dwSerialNumber;
        return FALSE;
    }

    // Update our record of the serial number and return TRUE.
    m_dwMediaID[nDrive] = dwSerialNumber;
    return TRUE;
}

BOOL CNGDriveView::IsPathValid (CString& strPathName)
{
    if (strPathName.GetLength () == 3)
        return TRUE;

    WIN32_FIND_DATA fd;
    BOOL bResult = FALSE;

	HANDLE hFind = ::FindFirstFile ((LPCTSTR) strPathName, &fd);
    if (INVALID_HANDLE_VALUE != hFind)
	{
		if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			bResult = TRUE;

		// Close the handle
		// This may cause a first chance exception
		// Hence the SEH handler around it....
		__try
		{
			::CloseHandle (hFind);
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			DWORD dwCode = GetExceptionCode();
			TRACE1("\tException Code: 0x%X\n", dwCode);
		}
    }
    return bResult;
}

void CNGDriveView::RefreshDirectory (HTREEITEM hItem)
{
    // If the item is not expanded, update its button state and return.
    if (!(GetTreeCtrl ().GetItemState (hItem, TVIS_EXPANDED) &
        TVIS_EXPANDED) || !GetTreeCtrl ().ItemHasChildren (hItem)) {
        if (!IsDriveNode (hItem)) {
            CString strPathName = GetPathFromItem (hItem);
            UpdateButtonState (hItem, strPathName);
            GetTreeCtrl ().Expand (hItem, TVE_COLLAPSE);
        }
        return;
    }

    // Delete items corresponding to subdirectories that no longer exist
    // and build a CStringList containing the names of all the items that
    // are children of hItem.
    CStringList list;
    WIN32_FIND_DATA fd;
    HANDLE hFind;

    HTREEITEM hChild = GetTreeCtrl ().GetChildItem (hItem);

    while (hChild != NULL) {
        HTREEITEM hNextItem = GetTreeCtrl ().GetNextSiblingItem (hChild);
        CString strDirName = GetTreeCtrl ().GetItemText (hChild);

        if ((hFind = ::FindFirstFile ((LPCTSTR) strDirName, &fd)) !=
            INVALID_HANDLE_VALUE) {
            if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                list.AddTail (strDirName);
            else
                GetTreeCtrl ().DeleteItem (hChild);
            ::FindClose (hFind);
        }
        else
            GetTreeCtrl ().DeleteItem (hChild);

        hChild = hNextItem;
    }

    // Add items for newly created subdirectories.
    if ((hFind = ::FindFirstFile ("*.*", &fd)) != INVALID_HANDLE_VALUE) {
        do {
            if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                CString strFileName = (LPCTSTR) &fd.cFileName;
                if ((strFileName != ".") && (strFileName != "..")) {
                    if (list.Find (strFileName) == NULL) {
                        hChild = GetTreeCtrl ().InsertItem (strFileName,
                            ILI_CLOSED_FOLDER, ILI_OPEN_FOLDER,
                            hItem, TVI_SORT);
                        CString strPathName = GetPathFromItem (hChild);
                        SetButtonState (hChild, strPathName);
                        list.AddTail (strFileName);
                    }
                }
            }
        } while (::FindNextFile (hFind, &fd));
    ::FindClose (hFind);
    }

    // Remove all items from the CStringList.
    list.RemoveAll ();

    // Now repeat this procedure for hItem's children.
    hChild = GetTreeCtrl ().GetChildItem (hItem);

    while (hChild != NULL) {
        CString string = GetTreeCtrl ().GetItemText (hChild);
        ::SetCurrentDirectory ((LPCTSTR) string);
        RefreshDirectory (hChild); // Recursion!
        ::SetCurrentDirectory ("..");
        hChild = GetTreeCtrl ().GetNextSiblingItem (hChild);
    }
}

void CNGDriveView::CreateMonitoringThread (CString& strDrive)
{
    PTHREADINFO pThreadInfo = new THREADINFO; // Thread will delete
    pThreadInfo->nDrive = (UINT) strDrive[0] - 0x41;
    pThreadInfo->hEvent = m_event.m_hObject;
    pThreadInfo->hWnd = m_hWnd;

    CWinThread* pThread = AfxBeginThread (ThreadFunc, pThreadInfo,
        THREAD_PRIORITY_IDLE);

    m_hThreads[m_nThreadCount++] = pThread->m_hThread;
}

/////////////////////////////////////////////////////////////////////////
// Thread function for detecting file system changes

UINT CNGDriveView::ThreadFunc (LPVOID pParam)
{
    PTHREADINFO pThreadInfo = (PTHREADINFO) pParam;
    UINT nDrive = pThreadInfo->nDrive;
    HANDLE hEvent = pThreadInfo->hEvent;
    HWND hWnd = pThreadInfo->hWnd;
    delete pThreadInfo;

    CString strDrive = "?:\\";
    strDrive.SetAt (0, (TCHAR)(0x41 + nDrive));
    
    // Get a handle to a file change notification object.
    HANDLE hChange = ::FindFirstChangeNotification ((LPCTSTR) strDrive,
        TRUE, FILE_NOTIFY_CHANGE_DIR_NAME);

    // Return now if ::FindFirstChangeNotification failed.
    if (hChange == INVALID_HANDLE_VALUE)
        return 1;

    HANDLE aHandles[2];
    aHandles[0] = hChange;
    aHandles[1] = hEvent;
    BOOL bContinue = TRUE;

    // Sleep until a file change notification wakes this thread or
    // m_event becomes set indicating it's time for the thread to end.
    while (bContinue) {
        if (::WaitForMultipleObjects (2, aHandles, FALSE, INFINITE) -
            WAIT_OBJECT_0 == 0) { // Respond to a change notification.
            ::PostMessage (hWnd, WM_USER, (WPARAM) nDrive, 0);
            ::FindNextChangeNotification (hChange);
        }
        else // Kill this thread (m_event became signaled).
            bContinue = FALSE;
    }

    // Close the file change notification handle and return.
    ::FindCloseChangeNotification (hChange);
    return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Anna-Jayne Metcalfe
Founder Riverblade Limited
United Kingdom United Kingdom
I haven't always written software for a living. When I graduated from Surrey University in 1989, it was with an Electronic Engineering degree, but unfortunately that never really gave me the opportunity to do anything particularly interesting (with the possible exception of designing Darth Vader's Codpiece * for the UK Army in 1990).
    * Also known as the Standard Army Bootswitch. But that's another story...
Since the opportunity arose to lead a software team developing C++ software for Avionic Test Systems in 1996, I've not looked back. More recently I've been involved in the development of subsea acoustic navigation systems, digital TV broadcast systems, port security/tracking systems, and most recently software development tools with my own company, Riverblade Ltd.
 
One of my personal specialities is IDE plug-in development. ResOrg was my first attempt at a plug-in, but my day to day work is with Visual Lint, an interactive code analysis tool environment with works within the Visual Studio and Eclipse IDEs or on build servers.
 
I love lots of things, but particularly music, photography and anything connected with history or engineering. I despise ignorant, intolerant and obstructive people - and it shows...I can be a bolshy cow if you wind me up the wrong way...Laugh | :laugh:
 
I'm currently based 15 minutes walk from the beach in Bournemouth on the south coast of England. Since I moved here I've grown to love the place - even if it is full of grockles in Summer!
Follow on   Twitter

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 10 Jan 2005
Article Copyright 2001 by Anna-Jayne Metcalfe
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid