Click here to Skip to main content
15,891,513 members
Articles / Desktop Programming / MFC
Article

FindWhen

Rate me:
Please Sign up or sign in to vote.
2.75/5 (4 votes)
14 Feb 20053 min read 43K   440   10   9
An article on finding files created before a date.

Sample Image

Introduction

The Windows Find function only finds files by the date they were modified that I was aware of, I wanted a function to find files by the date they were created or modified, so I wrote this program.

Background

I initially thought of using the DatePicker resource but it would take a lot of scrolling to get to a year in the past because you would have to scroll through every month. The spin control works a lot better for this purpose, you can scroll the year separately. The spin controls are initially set to today's date and there ranges set to (months) 1-12, (days) 1-31, and (years) 1970-2038. A CTime object range is limited to these values for the year; to extend the range you would have to use COleDateTime, its range is January 1, 100 - December 31, 9999.

Using the code

A folder browser is needed, so I copied DirDialog from Chris Maunder's Time Stamp program. You can use it in any application by including the DirDialog.h file in your program and calling it using:

void CFindWhenDlg::OnBrowse() 
{
    UpdateData(TRUE);

    CDirDialog dlg; 
    dlg.m_strTitle = _T("Choose directory");
    dlg.m_strSelDir = m_strFile;

    if (dlg.DoBrowse()) 
    {
        m_strFile = dlg.m_strPath;
        m_path = m_strFile;
        UpdateData(FALSE);
    }
}

The list control is confusing to most new programmers, the best and easiest to implement is from Progamming Windows with MFC by Jeff Prosise. Chapter 10 has an example program of using a structure to store your list items in, calling AddItem which uses MFC's LVN_GETDISPINFO callback which puts the displayable items in the list control and assigns each an address pointer that is later used to sort the items. When you click a column, LVN_COLUMNCLICK message is sent to your application where you can sort the items in ascending or descending order. The list control header has an arrow showing which direction we are going, this is done by:

// Set the sort icons
COLORMAP cm = {RGB(0, 0, 0), RGB(255, 165, 0)}; // Set to orange
m_imglstSortIcons.Create(9, 5, ILC_COLOR24 | ILC_MASK, 2, 0);
m_bmpUpArrow.LoadMappedBitmap(IDB_HDRUP, 0, &cm, 1);
m_nUpArrow = m_imglstSortIcons.Add(&m_bmpUpArrow, RGB(255, 255, 255));
m_bmpDownArrow.LoadMappedBitmap(IDB_HDRDOWN, 0, &cm, 1);
m_nDownArrow = m_imglstSortIcons.Add(&m_bmpDownArrow, RGB(255, 255, 255));

And later calling:

// Display or hide sort icon on column to be sorted
void CFindWhenDlg::SetSortIcon(int nCol)
{
    ASSERT(m_list1);
    CHeaderCtrl* pHeaderCtrl = m_list1.GetHeaderCtrl();
    ASSERT(pHeaderCtrl);

    HDITEM hdrItem;
    int    nPhysicalCol = nCol;
    int col;
    for (col = pHeaderCtrl->GetItemCount(); col >= 0; col--)
    {
        hdrItem.mask = HDI_FORMAT | HDI_IMAGE;
        pHeaderCtrl->GetItem(nPhysicalCol, &hdrItem);
        if (m_nSortColumn     != 0 &&
            m_nSortColumn - 1 == col)
        {
            hdrItem.iImage = m_nUpArrow;
            hdrItem.fmt    = hdrItem.fmt & HDF_JUSTIFYMASK |
                HDF_IMAGE | HDF_STRING | HDF_BITMAP_ON_RIGHT;
        }
        else if (m_nSortColumn     != 0 &&
                -m_nSortColumn - 1 == col)
        {
            hdrItem.iImage = m_nDownArrow;
            hdrItem.fmt    = hdrItem.fmt & HDF_JUSTIFYMASK |
                HDF_IMAGE | HDF_STRING | HDF_BITMAP_ON_RIGHT;
        }
        else
            hdrItem.fmt = hdrItem.fmt & HDF_JUSTIFYMASK | HDF_STRING;
        pHeaderCtrl->SetItem(col, &hdrItem);
    }
}

To show that the current search is created or modified, I added code to update the list header:

void CFindWhenDlg::SetHeaderText(TCHAR *tStr)
{
    HDITEM hdi;
    hdi.mask = HDI_TEXT;
    hdi.pszText = tStr;
    pHeaderCtrl->SetItem(1, &hdi);
}

Points of Interest

The CString CompareNoCase() function works well on the files names for the sort routine but it doesn't sort the string version of numeric data such as the date 02/07/2005, so I save the CTime value in my structure and display it using:

case 1:    //Date and Time
    {
        CString szCreated;
        if(m_lcid == 1033)
            szCreated = pItem->cCreated.Format("%m/%d/%Y");
        else
            szCreated = pItem->cCreated.Format("%d/%m/%y");
        lstrcpy(pDispInfo->item.pszText, szCreated);
    }
    break;

For those who prefer day/month/year format, the program gets local time info using LCID GetSystemDefaultLCID(). The value 1033 is SUBLANG_ENGLISH_US, LANG_ENGLISH. I tested it using 2057 which is SUBLANG_ENGLISH_UK, LANG_ENGLISH.

For the compare: pItem1->cCreated > pItem2->cCreated compares two integers.

Another problem found in this type of program is, the RecurseDirectories() thread is in a very busy loop and does not allow the WM_QUIT message to be processed. The following is added to theApp:

void CFindWhenApp::ProcessIdleMsg()
{
    MSG msg;
    while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        if (msg.message == WM_QUIT) //maybe already closing
        {
            ::PostQuitMessage(0);
            break;
        }
        if (!PreTranslateMessage(&msg)) //allow other messages to process
        {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }
    }
}

Now messages can be processed by calling ProcessIdleMsg inside of the loop. This didn't solve the problem of the search thread running after the window is closed, so I added a "panic" button to stop the search. Also, my program was using 100% of the CPU time, so I added a Sleep(10) to slow it down a little.

This program uses the Windows XP Themes that has a problem if you use the dwExStyle |= LVS_EX_GRIDLINES in your list control. The lines are not drawn when you scroll the list. I found in the MSDN Knowledge base, the following article: MSDN Knowledge base.

Credits

  • DirDialog - Chris Maunder.

History

  • 08 February - Version 1.0.
  • 12 February - Version 1.1. Added new functions, fixed bugs.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralFYI: Most of the world doesn't use American date format! Pin
Don Clugston10-Feb-05 12:13
Don Clugston10-Feb-05 12:13 
GeneralRe: FYI: Most of the world doesn't use American date format! Pin
Roger6510-Feb-05 12:19
Roger6510-Feb-05 12:19 
GeneralRe: FYI: Most of the world doesn't use American date format! Pin
Don Clugston10-Feb-05 12:52
Don Clugston10-Feb-05 12:52 
GeneralRe: FYI: Most of the world doesn't use American date format! Pin
John M. Drescher15-Feb-05 6:44
John M. Drescher15-Feb-05 6:44 
GeneralRe: FYI: Most of the world doesn't use American date format! Pin
Don Clugston15-Feb-05 11:47
Don Clugston15-Feb-05 11:47 
GeneralRe: FYI: Most of the world doesn't use American date format! Pin
WoR21-Feb-05 1:06
WoR21-Feb-05 1:06 
GeneralRe: FYI: Most of the world doesn't use American date format! Pin
Roger6515-Feb-05 3:54
Roger6515-Feb-05 3:54 
GeneralXP has find by creation date already Pin
Harold Bamford10-Feb-05 3:56
Harold Bamford10-Feb-05 3:56 
GeneralRe: XP has find by creation date already Pin
Roger6510-Feb-05 4:04
Roger6510-Feb-05 4:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.