Click here to Skip to main content
15,895,142 members
Articles / Desktop Programming / MFC

Find Word

Rate me:
Please Sign up or sign in to vote.
4.55/5 (5 votes)
6 Jan 20062 min read 59.1K   863   23  
Windows Find is a nice tool but sometimes you want a little more. This program/tool does just that.
// FindWordDlg.cpp : implementation file
//

#include "stdafx.h"
#include "FindWord.h"
#include "FindWordDlg.h"
#include "DirDialog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern CFindWordApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFindWordDlg dialog

CFindWordDlg::CFindWordDlg(CWnd* pParent /*=NULL*/)
	: CResizeDlg(CFindWordDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CFindWordDlg)
	m_edit1 = _T("");
	m_edit2 = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CFindWordDlg::DoDataExchange(CDataExchange* pDX)
{
	CResizeDlg::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CFindWordDlg)
	DDX_Control(pDX, IDC_COMBO1, m_combo1);
	DDX_Control(pDX, IDC_LIST2, m_list2);
	DDX_Text(pDX, IDC_EDIT1, m_edit1);
	DDX_Text(pDX, IDC_EDIT2, m_edit2);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CFindWordDlg, CResizeDlg)
	//{{AFX_MSG_MAP(CFindWordDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
	ON_BN_CLICKED(IDC_SEARCH, OnSearch)
	ON_WM_DESTROY()
	ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST2, OnGetdispinfoList2)
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST2, OnColumnclickList2)
	ON_WM_CTLCOLOR()
	ON_BN_CLICKED(IDC_NO_CASE, OnNoCase)
	ON_CBN_SELCHANGE(IDC_COMBO1, OnSelchangeCombo1)
	ON_NOTIFY(NM_DBLCLK, IDC_LIST2, OnDblclkList2)
	ON_BN_CLICKED(IDC_LOG_FILE, OnLogFile)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

CHeaderCtrl *pgHeaderCtrl = NULL;
/////////////////////////////////////////////////////////////////////////////
// CFindWordDlg message handlers

BOOL CFindWordDlg::OnInitDialog()
{
	CResizeDlg::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	bClick = FALSE;
	bNoCase = FALSE;
	bStop = FALSE;
	bLogFile = FALSE;	
	bSearch = FALSE;
	m_strFile = "C:\\";
	m_edit1 = m_strFile;
	UpdateData(FALSE);
	nCount = 0;

	// Buttons
	AddControl(IDOK, CST_REPOS, CST_REPOS, CST_NONE, CST_NONE, 0);
	AddControl(IDCANCEL, CST_REPOS, CST_REPOS, CST_NONE, CST_NONE, 0);
	AddControl(IDC_BROWSE, CST_REPOS, CST_REPOS, CST_NONE, CST_NONE, 0);
	AddControl(IDC_SEARCH, CST_REPOS, CST_REPOS, CST_NONE, CST_NONE, 0);

	// Edit Controls
	AddControl(IDC_EDIT1, CST_RESIZE, CST_RESIZE, CST_NONE, CST_NONE, 1);
	AddControl(IDC_EDIT2, CST_RESIZE, CST_RESIZE, CST_NONE, CST_NONE, 1);

	// Check Box
	AddControl(IDC_NO_CASE, CST_REPOS, CST_REPOS, CST_NONE, CST_NONE, 1);
	AddControl(IDC_LOG_FILE, CST_REPOS, CST_REPOS, CST_NONE, CST_NONE, 1);

	// List Box
	AddControl(IDC_LIST2, CST_RESIZE, CST_RESIZE, CST_NONE, CST_RESIZE, 1);

	// Combo Box
	AddControl(IDC_COMBO1, CST_REPOS, CST_REPOS, CST_NONE, CST_NONE, 1);

	// Static Control
	AddControl(IDC_STATIC_SEARCH, CST_NONE, CST_NONE, CST_NONE, CST_REPOS, 1);
	AddControl(IDC_SEARCH_STRING, CST_NONE, CST_NONE, CST_NONE, CST_NONE, 1);
	AddControl(IDC_SELECT_EXT, CST_REPOS, CST_REPOS, CST_NONE, CST_NONE, 1);

	m_combo1.AddString("*.*");
	m_combo1.AddString("*.cpp");
	m_combo1.AddString("*.h");
	m_combo1.AddString("*.log");
	m_combo1.AddString("*.txt");
	m_combo1.SetCurSel(0);
	// 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));

	DWORD dwExStyle;
	dwExStyle = m_list2.GetExtendedStyle();
	dwExStyle |= LVS_EX_GRIDLINES;
	dwExStyle |= LVS_EX_FULLROWSELECT;

	m_list2.SetExtendedStyle(dwExStyle);

	m_list2.SetBkColor(RGB(0, 0, 0));
	m_list2.SetTextBkColor(RGB(0, 0, 0));
	m_list2.SetTextColor(RGB(255, 255, 255));

	m_list2.InsertColumn(0, _T("File Name / Text String:"), LVCFMT_LEFT, 544);
	m_list2.InsertColumn(1, _T("Line Num."), LVCFMT_LEFT, 84);

	pHeaderCtrl = m_list2.GetHeaderCtrl();
	pgHeaderCtrl = pHeaderCtrl;
	pHeaderCtrl->SetImageList(&m_imglstSortIcons); // Sort Icon

	m_szaFiles.RemoveAll();

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CFindWordDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CResizeDlg::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CFindWordDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CResizeDlg::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CFindWordDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CFindWordDlg::OnBrowse() 
{
	// TODO: Add your control notification handler code here
    UpdateData(TRUE);

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

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

void CFindWordDlg::OnSearch() 
{
	// TODO: Add your control notification handler code here
	bSearch ^= TRUE;
	if (bSearch)
	{
		GetDlgItem(IDC_SEARCH)->SetWindowText("Abort");
		bStop = FALSE;	
	}
	else
	{
		GetDlgItem(IDC_SEARCH)->SetWindowText("Search");
		bStop = TRUE;
	}
	GetDlgItem(IDC_COMBO1)->GetWindowText(m_strExt);
	if(m_strExt.Left(1) == "*")
		m_strExt.Delete(0, 1);
	UpdateData(TRUE);
	m_strSearch = m_edit2;
	if(m_strSearch.IsEmpty())
	{
		AfxMessageBox("Search string was Empty,\nplease try again.");
		return;
	}
	if(bNoCase)
		m_strSearch.MakeLower();
	nCount = 0;
	FreeItemMemory();
	m_list2.DeleteAllItems();
	GetDlgItem(IDOK)->EnableWindow(FALSE);
	GetDlgItem(IDCANCEL)->EnableWindow(FALSE);
	RecurseDirectories(m_strFile);
	if(bLogFile)
		LogFiles();
	GetDlgItem(IDOK)->EnableWindow(TRUE);
	GetDlgItem(IDCANCEL)->EnableWindow(TRUE);
	GetDlgItem(IDC_STATIC_SEARCH)->SetWindowText("");
	m_list2.SetFocus();	
	GetDlgItem(IDC_SEARCH)->SetWindowText("Search");
	bSearch = FALSE;
}

void CFindWordDlg::OnSelchangeCombo1() 
{
	// TODO: Add your control notification handler code here
	int nIndex = m_combo1.GetCurSel();	
	CString str;
	int n;
	n = m_combo1.GetLBTextLen( nIndex );
	m_combo1.GetLBText( nIndex, str.GetBuffer(n) );
	str.ReleaseBuffer();

	m_strExt = str;
	if(m_strExt.Left(1) == "*")
		m_strExt.Delete(0, 1);
}

void CFindWordDlg::OnNoCase() 
{
	// TODO: Add your control notification handler code here
	bNoCase = TRUE;
}

void CFindWordDlg::RecurseDirectories(CString& strDir)
{
    CString strFilter = strDir;
    if (strFilter.Right (1) != _T ("\\"))
        strFilter += _T ("\\");
    strFilter += _T ("*.*");

	CString szFileName;
    CFileFind finder;
    BOOL bWorking = finder.FindFile(strFilter);
    while (bWorking)
    {
		theApp.ProcessIdleMsg();
		if(bStop)
		{
			finder.Close();
			Sleep(100);
			return;
		}
		CWaitCursor wait;

        bWorking = finder.FindNextFile();
        
        if (!finder.IsDots())
        {
            if (finder.IsDirectory())
                RecurseDirectories(finder.GetFilePath());
            else
			{
				szFileName = finder.GetFileName();
				szFullPath = finder.GetFilePath();
				
				int len = szFileName.GetLength();
				int pos = szFileName.ReverseFind('.');
				CString szExt = szFileName.Right(len - pos);
				if (szExt.CompareNoCase(m_strExt) == 0)
				{
					CompareFileDate(finder.GetFilePath());
					Sleep(10);	// Wait for List Control
				}
				if ((m_strExt == ".*") && (szExt != ".exe") &&
					(szExt != ".bmp"))
				{
					CompareFileDate(finder.GetFilePath());
					Sleep(10);	// Wait for List Control
				}
			}
        }
    }
	finder.Close();
}

BOOL CFindWordDlg::CompareFileDate(CString szFile)
{
	BOOL bRes = TRUE;
	CString szStr;
	CString szStrFormat;
	int len = 0;
	int line = 0;
	TRY
	{
		CStdioFile fd(szFile, CFile::modeRead);
		len = m_strFile.GetLength();
		szFile.Delete(0, len);
		GetDlgItem(IDC_STATIC_SEARCH)->SetWindowText(szFile);
		while (fd.ReadString(szStr))
		{
			line++;
			if (bNoCase)
				szStr.MakeLower();
			if (szStr.Find(m_strSearch, 0) > 0)
			{
				nCount++;
				m_nLineNumber = line;
				szStrFormat.Format("File: %s", szFile);
				AddItem(szStrFormat);
				m_szaFiles.Add(szFullPath);
				Sleep(1);
				nCount++;
				szStrFormat.Format("Text: %s", szStr);
				szStrFormat.Replace("\t", "        ");
				AddItem(szStrFormat);
				szStrFormat.Format("Ln# %.4d %s", line, szStr);
				m_szaFiles.Add(szStrFormat);
			}
		}
		fd.Close();
	}
	CATCH(CFileException, pEx)
	{
		if (pEx->m_cause == CFileException::sharingViolation)
		{
			bRes = FALSE;
		}
		else
		{
			pEx->ReportError();
			bRes = FALSE;
		}
	}
	CATCH_ALL(e)
	{
		e->ReportError();
		bRes = FALSE;
	}
	END_CATCH_ALL
	return bRes;
}

BOOL CFindWordDlg::AddItem(CString szFile)
{
	ITEMINFO *pItem;
	try {
		pItem = new ITEMINFO;
	}
	catch(CMemoryException* e) {
		e->Delete();
		return FALSE;
	}

	pItem->szFilename = szFile;
	pItem->nLineNumber = m_nLineNumber;

	LV_ITEM lvi;
	lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
	lvi.iItem = nCount;
	lvi.iSubItem = 0;
	lvi.iImage = 0;
	lvi.pszText = LPSTR_TEXTCALLBACK;
	lvi.lParam = (LPARAM) pItem;

	if(m_list2.InsertItem(&lvi) == -1)
		return FALSE;

	return TRUE;
}

void CFindWordDlg::OnGetdispinfoList2(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
	// TODO: Add your control notification handler code here
	if(pDispInfo->item.mask & LVIF_TEXT)
	{
		ITEMINFO* pItem = (ITEMINFO*) pDispInfo->item.lParam;

		switch(pDispInfo->item.iSubItem)
		{
		case 0:	//My Documents
			lstrcpy(pDispInfo->item.pszText, pItem->szFilename);
			break;

		case 1:	//Line Number
			{
				CString szLineNumber;
				szLineNumber.Format("%.6d", pItem->nLineNumber);
				lstrcpy(pDispInfo->item.pszText, szLineNumber);
			}
			break;

		default:
			AfxMessageBox("Error in Display Info!");
			break;
		}

	}	
	
	*pResult = 0;
}

void CFindWordDlg::OnColumnclickList2(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	int nSubItem = pNMListView->iSubItem;
	int nCol = nSubItem;
	nSubItem += 1;	// because of -0 = +0
	if(bClick)
	{
		m_nSortColumn = nSubItem;
		SetSortIcon(nCol);
		m_list2.SortItems(CompareFunc, nSubItem);
		bClick = FALSE;
	}
	else
	{
		m_nSortColumn = -nSubItem;
		SetSortIcon(nCol);
		m_list2.SortItems(CompareFunc, -nSubItem);
		bClick = TRUE;
	}
	
	*pResult = 0;
}

int CALLBACK CFindWordDlg::CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	ITEMINFO* pItem1;
	ITEMINFO* pItem2;

	if (lParamSort > 0)
	{
		pItem1 =(ITEMINFO*) lParam1;
		pItem2 =(ITEMINFO*) lParam2;
		lParamSort -= 1;	// if positive
	}
	else
	{
		pItem2 =(ITEMINFO*) lParam1;
		pItem1 =(ITEMINFO*) lParam2;
		lParamSort += 1;	// if negative
	}

	int nResult;

	switch(abs(lParamSort))
	{
	case 0:	//My Documents
		nResult = pItem1->szFilename.CompareNoCase(pItem2->szFilename);
		break;

	case 1:	//Line Number
		nResult = pItem1->nLineNumber > pItem2->nLineNumber;
		break;

	default:
		AfxMessageBox("Error in Compare!");
		break;
	}
	return nResult;
}

void CFindWordDlg::OnDblclkList2(NMHDR* pNMHDR, LRESULT* pResult) 
{
	// TODO: Add your control notification handler code here
	CWaitCursor wait;
	DWORD dwPos = ::GetMessagePos();
	CPoint pt((int) LOWORD(dwPos), (int) HIWORD(dwPos));
	m_list2.ScreenToClient(&pt);
	int nItem = m_list2.HitTest(pt);
	CString szFullPath = m_strFile;
	szFullPath += m_list2.GetItemText(nItem, 0);
	ShellExecute(m_hWnd, "open", szFullPath, NULL, NULL, SW_SHOWNORMAL);
	
	*pResult = 0;
}

// Display or hide sort icon on column to be sorted
void CFindWordDlg::SetSortIcon(int nCol)
{
	ASSERT(m_list2);
	CHeaderCtrl* pHeaderCtrl = m_list2.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);
    }
}

void CFindWordDlg::FreeItemMemory()
{
	int nItemCount = m_list2.GetItemCount();
	if(nItemCount)
	{
		for(int i = 0; i < nItemCount; i++)
			delete(ITEMINFO*)m_list2.GetItemData(i);
	}
}

void CFindWordDlg::OnDestroy() 
{
	// TODO: Add your message handler code here
	if(bLogFile)
		LogFiles();
	FreeItemMemory();

	CResizeDlg::OnDestroy();
}

HBRUSH CFindWordDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
	HBRUSH hbr = CResizeDlg::OnCtlColor(pDC, pWnd, nCtlColor);
	
	// TODO: Change any attributes of the DC here
	if (pWnd->GetDlgCtrlID() == IDC_STATIC)
	{
		// Set the text color to blue
		pDC->SetTextColor(RGB(0, 0, 255));
		// Set the background mode for text to transparent 
		// so background will show thru.
		pDC->SetBkMode(TRANSPARENT);
	}
		
	// TODO: Return a different brush if the default is not desired
	return hbr;
}

void CFindWordDlg::OnLogFile() 
{
	// TODO: Add your control notification handler code here
	bLogFile = TRUE;	
}

void CFindWordDlg::LogFiles()
{
	CStdioFile fd;
	CString szFile;
	
	fd.Open("Log.txt", CFile::modeCreate | CFile::modeWrite);
	if(!fd)
	{
		AfxMessageBox("Couldn't open output file!");
			return;
	}
	for(int index = 0; index < m_szaFiles.GetSize(); index++)
	{
		szFile = m_szaFiles.GetAt(index);
		szFile += "\n";
		fd.WriteString(szFile);
	}
	fd.Close();
}

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 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