Click here to Skip to main content
15,886,823 members
Articles / Desktop Programming / MFC

CFileInfoArray: A class for gathering file information recursively through directories

Rate me:
Please Sign up or sign in to vote.
4.81/5 (20 votes)
23 Nov 199910 min read 160.8K   7.2K   102  
This class gathers file information recursively by directory and, as a bonus track, it also calculates the 32bit file-checksum and CRC
// FCompareDlg.cpp : implementation file
// (c) Codeguru & friends
// Coded by Antonio Tejada Lacaci. 1999
// atejada@espanet.com
//

#include "stdafx.h"
#include "FCompare.h"
#include "FCompareDlg.h"
#include "DirDialog.h"
#include <Shlwapi.h>

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

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

#include "HyperLink.h"

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

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	CHyperLink m_urlHomepage;
	CHyperLink m_urlCodeguru;
	//}}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)
	DDX_Control(pDX, URL_HOMEPAGE, m_urlHomepage);
	DDX_Control(pDX, URL_CODEGURU, m_urlCodeguru);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFCompareDlg dialog

CFCompareDlg::CFCompareDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CFCompareDlg::IDD, pParent) {
	//{{AFX_DATA_INIT(CFCompareDlg)
	m_bRecurse = FALSE;
	m_nMatchCriteria = 0;
	m_dwUpto = 0;
	m_strAllowedMasks = _T("*.*");
	m_strDirectory = _T("");
	m_bCompareDuplicates = FALSE;
	//}}AFX_DATA_INIT
   m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

   // Flags
   m_bExit = FALSE;
   m_bAbort = FALSE;
   m_bAddInProgress = FALSE;
   m_bFillInProgress = FALSE;
   m_bCompareInProgress = FALSE;
   m_bsState = BS_IDLE;

   // Logical data
   m_msaMatchedInfos.SetSize(0,20);
}

void CFCompareDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CFCompareDlg)
	DDX_Control(pDX, LBL_STATUS, m_lblStatus);
	DDX_Control(pDX, LBL_TARGETFILES, m_lblTargetFiles);
	DDX_Control(pDX, LBL_SOURCEFILES, m_lblSourceFiles);
	DDX_Control(pDX, LBL_MATCHEDFILES, m_lblMatchedFiles);
	DDX_Control(pDX, LST_MATCHEDFILES, m_lstMatchedFiles);
	DDX_Control(pDX, TAB_ACTION, m_tabAction);
	DDX_Control(pDX, LST_TARGETFILES, m_lstTargetFiles);
	DDX_Control(pDX, LST_SOURCEFILES, m_lstSourceFiles);
	DDX_Control(pDX, PRG_PROGRESS, m_prgProgress);
	DDX_Check(pDX, CHK_RECURSEDIR, m_bRecurse);
	DDX_Radio(pDX, RAD_MATCHCRITERIA, m_nMatchCriteria);
	DDX_Text(pDX, EDT_UPTO, m_dwUpto);
	DDX_Text(pDX, EDT_ALLOWEDMASKS, m_strAllowedMasks);
	DDX_Text(pDX, EDT_DIRECTORY, m_strDirectory);
	DDX_Check(pDX, CHK_COMPAREDUPLICATES, m_bCompareDuplicates);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CFCompareDlg, CDialog)
	//{{AFX_MSG_MAP(CFCompareDlg)
   ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(RAD_MATCHCONTENTS, OnMatchContents)
	ON_BN_CLICKED(RAD_MATCHCRITERIA, OnMatchCriteria)
	ON_BN_CLICKED(BTN_COMPARE, OnCompare)
	ON_WM_TIMER()
	ON_NOTIFY(LVN_GETDISPINFO, LST_SOURCEFILES, OnGetdispinfoSearchFiles)
	ON_BN_CLICKED(BTN_EXIT, OnExit)
	ON_NOTIFY(TCN_SELCHANGE, TAB_ACTION, OnSelchangeAction)
	ON_NOTIFY(LVN_GETDISPINFO, LST_MATCHEDFILES, OnGetdispinfoMatchedFiles)
	ON_BN_CLICKED(BTN_EXPLOREDIR, OnExploreDirectory)
	ON_BN_CLICKED(BTN_ADDSOURCEFILES, OnAddSourceFiles)
	ON_BN_CLICKED(BTN_ADDTARGETFILES, OnAddTargetFiles)
	ON_BN_CLICKED(BTN_CLEARSOURCEFILES, OnClearSourceFiles)
	ON_BN_CLICKED(BTN_CLEARTARGETFILES, OnClearTargetFiles)
	ON_WM_CLOSE()
	ON_NOTIFY(LVN_GETDISPINFO, LST_TARGETFILES, OnGetdispinfoSearchFiles)
	ON_BN_CLICKED(RAD_MATCHCHECKSUM, OnMatchContents)
	ON_BN_CLICKED(RAD_MATCHCRC, OnMatchContents)
	ON_BN_CLICKED(BTN_EXPORT, OnExport)
	//}}AFX_MSG_MAP
   ON_MESSAGE(WM_SEARCH_FINISHED, OnSearchFinished)
   ON_MESSAGE(WM_COMPARE_FINISHED, OnCompareFinished)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFCompareDlg message handlers

BOOL CFCompareDlg::OnInitDialog() {
	CDialog::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);
		}
      // Invalidate maximize & resize
      pSysMenu->EnableMenuItem(SC_SIZE,MF_GRAYED);
      pSysMenu->EnableMenuItem(SC_MAXIMIZE,MF_GRAYED);
      pSysMenu->EnableMenuItem(SC_RESTORE,MF_GRAYED);
	}

	// 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
	
   m_lstSourceFiles.InsertColumn(0,_T("Filename"),LVCFMT_LEFT,300);
   m_lstSourceFiles.InsertColumn(1,_T("Size"),LVCFMT_RIGHT,65);

   m_lstTargetFiles.InsertColumn(0,_T("Filename"),LVCFMT_LEFT,300);
   m_lstTargetFiles.InsertColumn(1,_T("Size"),LVCFMT_RIGHT,65);

   m_lstMatchedFiles.InsertColumn(0,_T("Source Filename"),LVCFMT_LEFT,268);
   m_lstMatchedFiles.InsertColumn(1,_T("Target Filename"),LVCFMT_LEFT,268);
   m_lstMatchedFiles.InsertColumn(2,_T("Size"),LVCFMT_RIGHT,65);

   UpdateCounters();

   m_tabAction.InsertItem(PPG_SEARCH,_T(" Search "));
   m_tabAction.InsertItem(PPG_COMPARE,_T(" Compare "));

   GetDlgItem(LBL_TARGETFILES)->ShowWindow(SW_SHOW);
   GetDlgItem(LBL_SOURCEFILES)->ShowWindow(SW_SHOW);
   GetDlgItem(LST_TARGETFILES)->ShowWindow(SW_SHOW);
   GetDlgItem(LST_SOURCEFILES)->ShowWindow(SW_SHOW);
   GetDlgItem(CHK_RECURSEDIR)->ShowWindow(SW_SHOW);
   GetDlgItem(BTN_COMPARE)->ShowWindow(SW_SHOW);
   GetDlgItem(LBL_MATCHEDFILES)->ShowWindow(SW_HIDE);
   GetDlgItem(LST_MATCHEDFILES)->ShowWindow(SW_HIDE);

   UpdateData(FALSE);
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CFCompareDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::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 CFCompareDlg::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 {
		CDialog::OnPaint();
	}
}

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

void CFCompareDlg::OnExploreDirectory() {
   CDirDialog dlgDir;
   
   dlgDir.m_strTitle = _T("Select directory for file search");
   UpdateData(TRUE);
   dlgDir.m_strSelDir = m_strDirectory;
   dlgDir.m_strWindowTitle = _T("Select directory");
   if (dlgDir.DoBrowse(this) == IDOK) {
      m_strDirectory = dlgDir.m_strPath;
      // Append backslash if necessary
      if ((m_strDirectory.GetLength()>0) && 
          (m_strDirectory[m_strDirectory.GetLength()-1] != TCHAR('\\'))) 
          m_strDirectory += TCHAR('\\');
      UpdateData(FALSE);
   }
}

void CFCompareDlg::OnMatchContents() {
   GetDlgItem(EDT_UPTO)->EnableWindow(TRUE);	
}

void CFCompareDlg::OnMatchCriteria() {
   GetDlgItem(EDT_UPTO)->EnableWindow(FALSE);
}

UINT SearchThread(CFCompareDlg *pcdlg) {
   // Retrieve directories
   LVITEM lvi;
   CString strMask;
   int nPos=0;
   int nNextPos=0;

   memset(&lvi,0,sizeof(lvi));
   pcdlg->m_bAddInProgress = TRUE;

   // Delete files' listview (if files were added, listviews are no longer up to date due 
   // to possible reordering of items in FileInfoArray).
   pcdlg->m_plstFiles->DeleteAllItems();

   // Retrieve files: Sorted by size and ascending, do not include dirs.
   while (nPos < pcdlg->m_strAllowedMasks.GetLength()) {
      nNextPos = pcdlg->m_strAllowedMasks.Find(";",nPos);
      if (nNextPos == -1) nNextPos = pcdlg->m_strAllowedMasks.GetLength();
      strMask = pcdlg->m_strAllowedMasks.Mid(nPos, nNextPos-nPos);
      strMask.TrimLeft();
      strMask.TrimRight();
      TRACE("strMask is %s\n",strMask);
      if (strMask != "")
         pcdlg->m_pfiaInfos->AddDir(pcdlg->m_strDirectory, strMask, pcdlg->m_bRecurse, 
            CFileInfoArray::AP_SORTBYSIZE | CFileInfoArray::AP_SORTASCENDING, FALSE, 
            &pcdlg->m_bAbort);
      nPos = nNextPos+1;
   }

   pcdlg->m_lblStatus.SetWindowText(_T("Filling listview..."));

   pcdlg->m_ulProgress = 0;
   pcdlg->m_ulProgressMax = pcdlg->m_pfiaInfos->GetSize();

   pcdlg->m_bAddInProgress = FALSE;
   pcdlg->m_bFillInProgress = TRUE;
   

   // Set common LVITEM attributes
   lvi.pszText = LPSTR_TEXTCALLBACK;
   lvi.mask = LVIF_TEXT | LVIF_PARAM;
   lvi.iSubItem = 0;

   // Insert files
   pcdlg->m_plstFiles->LockWindowUpdate();
   for (int i=0;((i<pcdlg->m_pfiaInfos->GetSize()) && (!pcdlg->m_bAbort));i++) {
      lvi.iItem = i;
      lvi.lParam = (LPARAM) &(*pcdlg->m_pfiaInfos)[i];
      pcdlg->m_plstFiles->InsertItem(&lvi);
      pcdlg->m_ulProgress++;
   }
   pcdlg->m_plstFiles->UnlockWindowUpdate();

   pcdlg->m_bFillInProgress = FALSE;
   pcdlg->PostMessage(WM_SEARCH_FINISHED);
   return 0;
}

BOOL CompareContents(CFileInfo* pfinSrc, CFileInfo* pfinDest, const DWORD dwUpTo, 
   volatile BOOL* pbAbort) {
   // Note this method is not "win64 friendly"
   FILE* fSrc;
   FILE* fDest;
   DWORD dwCount = 0;
   BYTE cSrc, cDest;

   if ((dwUpTo == 0) || (dwUpTo > pfinSrc->GetLength())) 
      dwCount = pfinSrc->GetLength();
   else
      dwCount = dwUpTo;

   fSrc = fopen(pfinSrc->GetFilePath(),"rb");
   fDest = fopen(pfinDest->GetFilePath(),"rb");
   if (fSrc && fDest) {
      while (!feof(fSrc) && !feof(fDest) && !(*pbAbort) && (dwCount>0) && 
         fread(&cSrc,1,1,fSrc) && fread(&cDest,1,1,fDest) && (cSrc == cDest)) {
         dwCount--;
      }
   }
   if (fSrc) fclose(fSrc);
   if (fDest) fclose(fDest);
   return (dwCount == 0);
}

UINT CompareThread(CFCompareDlg *pcdlg) {
   CFileInfo* pfinSource;
   CFileInfo* pfinTarget;
   MATCHSTRUCT ms;
   DWORD dwMatchSize=0;
   DWORD dwMatchNumber=0;
   LVITEM lviMatched;
   // Compare
   
   int iSource=0;
   int iTarget=0;

   pcdlg->m_bCompareInProgress = TRUE;
   pcdlg->m_ulProgress = 0;
   pcdlg->m_ulProgressMax = pcdlg->m_fiaSourceInfos.GetSize() + 
      pcdlg->m_fiaTargetInfos.GetSize();

   while ((!pcdlg->m_bAbort) && 
          (iSource<pcdlg->m_fiaSourceInfos.GetSize()) && 
          (iTarget<pcdlg->m_fiaTargetInfos.GetSize())) {

      pfinSource = &pcdlg->m_fiaSourceInfos[iSource];
      pfinTarget = &pcdlg->m_fiaTargetInfos[iTarget];

      // Compare pfinSource with all the files of target with the same size of pfinSource
      for (int i=iTarget;(i<pcdlg->m_fiaTargetInfos.GetSize()) && 
         (pcdlg->m_fiaTargetInfos[i].GetLength64() == pfinSource->GetLength64());i++) {
         pfinTarget = &pcdlg->m_fiaTargetInfos[i];
         if (// Not the same file or Ignore duplicates unchecked
             (pcdlg->m_bCompareDuplicates ||
              (pfinSource->GetFilePath().CompareNoCase(pfinTarget->GetFilePath()) != 0)) &&
             // Checksum criteria
             ((pcdlg->m_nMatchCriteria != 1) || 
             (pfinSource->GetChecksum(pcdlg->m_dwUpto, FALSE, &pcdlg->m_bAbort) == 
              pfinTarget->GetChecksum(pcdlg->m_dwUpto, FALSE, &pcdlg->m_bAbort))) &&
             // CRC criteria
             ((pcdlg->m_nMatchCriteria != 2) || 
             (pfinSource->GetCRC(pcdlg->m_dwUpto, FALSE, &pcdlg->m_bAbort) == 
              pfinTarget->GetCRC(pcdlg->m_dwUpto, FALSE, &pcdlg->m_bAbort))) &&
             // Contents criteria
             ((pcdlg->m_nMatchCriteria != 3) || 
             (CompareContents(pfinSource, pfinTarget, pcdlg->m_dwUpto, &pcdlg->m_bAbort)))
             ) {
             // Match!
             ms.pfinTarget = pfinTarget;
             ms.pfinSource = pfinSource;
             pcdlg->m_msaMatchedInfos.InsertAt(pcdlg->m_msaMatchedInfos.GetSize(), ms);
             dwMatchSize += pfinTarget->GetLength();
             dwMatchNumber++;
         }
      }
      // Restore initial target
      pfinTarget = &pcdlg->m_fiaTargetInfos[iTarget];
      
      if (pfinTarget->GetLength64() >= pfinSource->GetLength64())
         iSource++; // In case of equal sizes, iSource must be incremented first 
                    // (see inner loop for reasons)
      else
         iTarget++;

      pcdlg->m_ulProgress++;
   }

   // Set new progress values
   pcdlg->m_ulProgress = 0;
   pcdlg->m_ulProgressMax = pcdlg->m_msaMatchedInfos.GetSize();

   pcdlg->m_bCompareInProgress = FALSE;
   pcdlg->m_bFillInProgress = TRUE;
   
   // Fill listview
   pcdlg->m_lblStatus.SetWindowText(_T("Filling listview..."));
   pcdlg->m_lstMatchedFiles.LockWindowUpdate();
   // Set common LVITEM values for all elements
   lviMatched.mask = LVIF_PARAM | LVIF_TEXT;
   lviMatched.iSubItem = 0;
   lviMatched.pszText = LPSTR_TEXTCALLBACK;
   for (int i=0;(i<pcdlg->m_msaMatchedInfos.GetSize()) && (!pcdlg->m_bAbort);i++) {
      lviMatched.iItem = i;
      lviMatched.lParam = (LPARAM) &pcdlg->m_msaMatchedInfos[i];
      pcdlg->m_lstMatchedFiles.InsertItem(&lviMatched);
      pcdlg->m_ulProgress++;
   }
   pcdlg->m_lstMatchedFiles.UnlockWindowUpdate();
   pcdlg->m_bFillInProgress = FALSE;

   // Report compare thread end
   pcdlg->PostMessage(WM_COMPARE_FINISHED,dwMatchNumber, dwMatchSize);
   return 0;
}

void CFCompareDlg::SetBusyState(int m_bsState) {
   this->m_bsState = m_bsState;

   GetDlgItem(LST_SOURCEFILES)->EnableWindow(m_bsState != BS_SEARCHING);
   GetDlgItem(LST_TARGETFILES)->EnableWindow(m_bsState != BS_SEARCHING);
   GetDlgItem(CHK_RECURSEDIR)->EnableWindow(m_bsState != BS_SEARCHING);

   GetDlgItem(BTN_COMPARE)->EnableWindow(m_bsState == BS_IDLE);
   GetDlgItem(BTN_CLEARSOURCEFILES)->EnableWindow(m_bsState == BS_IDLE);
   GetDlgItem(BTN_CLEARTARGETFILES)->EnableWindow(m_bsState == BS_IDLE);
   GetDlgItem(BTN_ADDSOURCEFILES)->EnableWindow(m_bsState == BS_IDLE);
   GetDlgItem(BTN_ADDTARGETFILES)->EnableWindow(m_bsState == BS_IDLE);
   GetDlgItem(BTN_EXPORT)->EnableWindow(m_bsState == BS_IDLE);

   GetDlgItem(RAD_MATCHCRITERIA)->EnableWindow(m_bsState != BS_COMPARING);
   GetDlgItem(RAD_MATCHCHECKSUM)->EnableWindow(m_bsState != BS_COMPARING);
   GetDlgItem(RAD_MATCHCRC)->EnableWindow(m_bsState != BS_COMPARING);
   GetDlgItem(RAD_MATCHCONTENTS)->EnableWindow(m_bsState != BS_COMPARING);
   GetDlgItem(EDT_UPTO)->EnableWindow((m_bsState != BS_COMPARING) && 
      (IsDlgButtonChecked(RAD_MATCHCRITERIA) != BST_CHECKED));
   GetDlgItem(CHK_COMPAREDUPLICATES)->EnableWindow(m_bsState != BS_COMPARING);

   if (m_bsState != BS_IDLE) {
      GetDlgItem(BTN_EXIT)->SetWindowText(_T("Cancel"));
   } else {
      GetDlgItem(BTN_EXIT)->SetWindowText(_T("Exit"));
      m_lblStatus.SetWindowText(_T("Ready"));
      m_prgProgress.SetPos(0);
   }
}


void CFCompareDlg::UpdateCounters() {
   CString str;

   str.Format(_T("Matched files (%d)"), m_lstMatchedFiles.GetItemCount());
   GetDlgItem(LBL_MATCHEDFILES)->SetWindowText(str);
   str.Format(_T("Source files (%d)"), m_lstSourceFiles.GetItemCount());
   GetDlgItem(LBL_SOURCEFILES)->SetWindowText(str);
   str.Format(_T("Target files (%d)"), m_lstTargetFiles.GetItemCount());
   GetDlgItem(LBL_TARGETFILES)->SetWindowText(str);
}

void CFCompareDlg::OnCompare() {
   // Retrieve comparison settings
   UpdateData(TRUE);
   m_lblStatus.SetWindowText(_T("Comparing files..."));

   // Empty compare list
   m_lstMatchedFiles.DeleteAllItems();
   m_msaMatchedInfos.RemoveAll();

   m_bAbort = FALSE;
   SetBusyState(BS_COMPARING);

   // Launch thread
   AfxBeginThread((AFX_THREADPROC) CompareThread,(LPVOID) this);
   // Launch progress-report timer
   if (SetTimer(1,250, NULL) == 0){
      // Timer not available
      AfxMessageBox(_T("Timer is not available, real time progress will not be reported."), 
         MB_ICONINFORMATION | MB_OK);
   }
}

void CFCompareDlg::OnGetdispinfoSearchFiles(NMHDR* pNMHDR, LRESULT* pResult) {
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
   CString str;
   CFileInfo* pinf;

   pinf = (CFileInfo*) pDispInfo->item.lParam;
   switch (pDispInfo->item.iSubItem) {
      case 0:
         pDispInfo->item.mask = LVIF_TEXT;
         StrCpyN(pDispInfo->item.pszText, pinf->GetFilePath(), pDispInfo->item.cchTextMax);
      break;
      case 1:
         if (pinf->GetLength64() < 1024) 
            str.Format("%d   B", pinf->GetLength());
         else {
            // The following weird LONGLONG casts are because VC 6.0 doesn't implement int64 
            // to double conversion =8-ooo
            if (pinf->GetLength64() < (1024*1024))
               str.Format("%3.2f KB",(LONGLONG) pinf->GetLength64() / 1024.0);
            else {
               if (pinf->GetLength64() < (1024*1024*1024))
                  str.Format("%3.2f MB", (LONGLONG) pinf->GetLength64() / (1024*1024.0));
               else
                  str.Format("%1.2f GB", (LONGLONG) pinf->GetLength64() / (1024.0*1024*1024));
            }
         }     
         pDispInfo->item.mask = LVIF_TEXT;

         StrCpyN(pDispInfo->item.pszText, str, pDispInfo->item.cchTextMax);
      break;
   }
	
	*pResult = 0;
}

void CFCompareDlg::OnTimer(UINT nIDEvent) {
   CString str;

   if (m_bAddInProgress) {
      str.Format(_T("Found %d files"),m_fiaSourceInfos.GetSize() + m_fiaTargetInfos.GetSize());
      m_lblStatus.SetWindowText(str);
      str.Format(_T("Source files (%d)"), m_fiaSourceInfos.GetSize());
      m_lblSourceFiles.SetWindowText(str);
      str.Format(_T("Target files (%d)"), m_fiaTargetInfos.GetSize());
      m_lblTargetFiles.SetWindowText(str);
   }

   if (m_bFillInProgress) {
      m_prgProgress.SetRange(0, (short) m_ulProgressMax);
      m_prgProgress.SetPos(m_ulProgress);
   }

   if (m_bCompareInProgress) {
      str.Format(_T("Matched %d files"), m_msaMatchedInfos.GetSize());
      m_lblStatus.SetWindowText(str);
      str.Format(_T("Matched files (%d)"), m_msaMatchedInfos.GetSize());
      m_lblMatchedFiles.SetWindowText(str);
      m_prgProgress.SetRange(0, (short) m_ulProgressMax);
      m_prgProgress.SetPos(m_ulProgress);
   }

	CDialog::OnTimer(nIDEvent);
}

afx_msg LONG CFCompareDlg::OnSearchFinished(WPARAM /* wparam*/ , LPARAM /* lparam */) {
   if (m_bAbort) {
      // Delete items from aborted listview
      m_plstFiles->DeleteAllItems();
      // Delete items from aborted CFileInfoArray
      m_pfiaInfos->RemoveAll();
   }

   KillTimer(1);
   SetBusyState(BS_IDLE);

   m_lblStatus.SetWindowText(_T("Ready"));
   UpdateCounters();
   if (m_bExit) PostQuitMessage(0);
   return TRUE;
}

afx_msg LONG CFCompareDlg::OnCompareFinished(WPARAM wparam, LPARAM lparam) {
   CString str;

   if (m_bAbort)
      m_lstMatchedFiles.DeleteAllItems();

   KillTimer(1);
   SetBusyState(BS_IDLE);

   if (!m_bAbort) {
      str.Format(_T("Comparison results:\r\n* %d files matched\r\n* %d bytes matched"),
         wparam, lparam);

      MessageBox(str,_T("Comparison ended"),MB_OK);
   }

   m_prgProgress.SetPos(0);

   str.Format(_T("Matched files (%d)"),m_lstMatchedFiles.GetItemCount());
   m_lblMatchedFiles.SetWindowText(str);
   
   UpdateCounters();
   if (m_bExit) PostQuitMessage(0);
   return TRUE;
}

void CFCompareDlg::OnExit() {
   if (m_bsState == BS_IDLE) PostQuitMessage(0);
   m_bAbort = TRUE;
}

void CFCompareDlg::OnSelchangeAction(NMHDR* /* pNMHDR*/, LRESULT* pResult) {
   if (m_tabAction.GetCurSel() == PPG_COMPARE) {
      GetDlgItem(LBL_TARGETFILES)->ShowWindow(SW_HIDE);
      GetDlgItem(LBL_SOURCEFILES)->ShowWindow(SW_HIDE);
      GetDlgItem(LST_TARGETFILES)->ShowWindow(SW_HIDE);
      GetDlgItem(LST_SOURCEFILES)->ShowWindow(SW_HIDE);
      GetDlgItem(BTN_COMPARE)->ShowWindow(SW_HIDE);
      GetDlgItem(LBL_MATCHEDFILES)->ShowWindow(SW_SHOW);
      GetDlgItem(LST_MATCHEDFILES)->ShowWindow(SW_SHOW);
      GetDlgItem(CHK_COMPAREDUPLICATES)->ShowWindow(SW_HIDE);
   } else {
      GetDlgItem(LBL_TARGETFILES)->ShowWindow(SW_SHOW);
      GetDlgItem(LBL_SOURCEFILES)->ShowWindow(SW_SHOW);
      GetDlgItem(LST_TARGETFILES)->ShowWindow(SW_SHOW);
      GetDlgItem(LST_SOURCEFILES)->ShowWindow(SW_SHOW);
      GetDlgItem(BTN_COMPARE)->ShowWindow(SW_SHOW);
      GetDlgItem(LBL_MATCHEDFILES)->ShowWindow(SW_HIDE);
      GetDlgItem(LST_MATCHEDFILES)->ShowWindow(SW_HIDE);
      GetDlgItem(CHK_COMPAREDUPLICATES)->ShowWindow(SW_SHOW);
   }
	*pResult = 0;
}

void CFCompareDlg::OnGetdispinfoMatchedFiles(NMHDR* pNMHDR, LRESULT* pResult)  {
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
   MATCHSTRUCT* pms;
   CFileInfo* pinf;
   CString str;

	switch (pDispInfo->item.iSubItem) {
      case 0:
         pDispInfo->item.mask = LVIF_TEXT;
         pms = (MATCHSTRUCT*) pDispInfo->item.lParam;
         StrCpyN(pDispInfo->item.pszText, pms->pfinSource->GetFilePath(), 
            pDispInfo->item.cchTextMax);
      break;
      case 1:
         pDispInfo->item.mask = LVIF_TEXT;
         pms = (MATCHSTRUCT*) pDispInfo->item.lParam;
         StrCpyN(pDispInfo->item.pszText, pms->pfinTarget->GetFilePath(), 
            pDispInfo->item.cchTextMax);
      break;
      case 2:
         pms = (MATCHSTRUCT*) pDispInfo->item.lParam;
         pinf = pms->pfinSource;

         if (pinf->GetLength64() < 1024) 
            str.Format("%d   B",pinf->GetLength());
         else {
            // The following weird LONGLONG casts are because VC 6.0 doesn't implement int64 
            // to double conversion =8-ooo
            if (pinf->GetLength64() < (1024*1024))
               str.Format("%3.2f KB",(LONGLONG) pinf->GetLength64() / 1024.0);
            else {
               if (pinf->GetLength64() < (1024*1024*1024))
                  str.Format("%3.2f MB", (LONGLONG) pinf->GetLength64() / (1024*1024.0));
               else
                  str.Format("%1.2f GB", (LONGLONG) pinf->GetLength64() / (1024.0*1024*1024));
            }
         }     
         pDispInfo->item.mask = LVIF_TEXT;

         StrCpyN(pDispInfo->item.pszText, str, pDispInfo->item.cchTextMax);
      break;
   }
	
	*pResult = 0;
}

void CFCompareDlg::OnAddSourceFiles() {
   // Retrieve search settings from dialog controls
   UpdateData(TRUE);

   // Append backslash if necessary
   if ((m_strDirectory.GetLength()>0) && 
       (m_strDirectory[m_strDirectory.GetLength()-1] != TCHAR('\\'))) m_strDirectory += TCHAR('\\');
   UpdateData(FALSE);

   // Set common variables with thread
   m_plstFiles = &m_lstSourceFiles;
   m_pfiaInfos = &m_fiaSourceInfos;

   // Compare text-callback list will no longer be up to date, empty it
   m_lstMatchedFiles.DeleteAllItems();
   m_msaMatchedInfos.RemoveAll();
   m_lblStatus.SetWindowText(_T("Inserting files..."));

   m_bAbort = FALSE;
   SetBusyState(BS_SEARCHING);

   // Launch thread
   AfxBeginThread((AFX_THREADPROC) SearchThread,(LPVOID) this);
   // Launch progress-report timer
   if (SetTimer(1,250, NULL) == 0){
      // Timer not available
      AfxMessageBox(_T("Timer is not available, real time progress will not be reported."), 
         MB_ICONINFORMATION | MB_OK);
   }
}

void CFCompareDlg::OnAddTargetFiles() {
   // Retrieve search settings from dialog controls
   UpdateData(TRUE);

   // Append backslash if necessary
   if ((m_strDirectory.GetLength()>0) && 
       (m_strDirectory[m_strDirectory.GetLength()-1] != TCHAR('\\'))) m_strDirectory += TCHAR('\\');
   UpdateData(FALSE);

   // Set common variables with thread
   m_plstFiles = &m_lstTargetFiles;
   m_pfiaInfos = &m_fiaTargetInfos;

   // Compare text-callback list will no longer be up to date, empty it
   m_lstMatchedFiles.DeleteAllItems();
   m_msaMatchedInfos.RemoveAll();
   m_lblStatus.SetWindowText(_T("Inserting files..."));

   m_bAbort = FALSE;
   SetBusyState(BS_SEARCHING);

   // Launch thread
   AfxBeginThread((AFX_THREADPROC) SearchThread,(LPVOID) this);
   // Launch progress-report timer
   if (SetTimer(1,250, NULL) == 0){
      // Timer not available
      AfxMessageBox(_T("Timer is not available, real time progress will not be reported."), 
         MB_ICONINFORMATION | MB_OK);
   }
}

void CFCompareDlg::OnClearSourceFiles() {
   // Clear matched
   m_lstMatchedFiles.DeleteAllItems();
   m_msaMatchedInfos.RemoveAll();
   // Clear listview
   m_lstSourceFiles.DeleteAllItems();
   // Clear fileinfos array
   m_fiaSourceInfos.RemoveAll();
   // UpdateCounters
   UpdateCounters();
}

void CFCompareDlg::OnClearTargetFiles() {
   // Clear matched
   m_lstMatchedFiles.DeleteAllItems();
   m_msaMatchedInfos.RemoveAll();
   // Clear listview
   m_lstTargetFiles.DeleteAllItems();
   // Clear fileinfos array
   m_fiaTargetInfos.RemoveAll();
   // Update counters
   UpdateCounters();
}

void CFCompareDlg::OnClose() {
   if (m_bsState != BS_IDLE) {
      // Thread running, signal abort and exit flag
      m_bExit = TRUE;
      m_bAbort = TRUE;
   } else
	   CDialog::OnClose();
}

void CFCompareDlg::OnExport() {
   CStdioFile sf;
   CFileDialog fd(FALSE);
   int i;
   CString str;

   if (fd.DoModal() == IDOK) {
      try {
         sf.Open(fd.m_ofn.lpstrFile, CStdioFile::modeWrite | CFile::modeCreate | CStdioFile::typeText);
         sf.WriteString(_T("SOURCE FILES:\n"));
         for (i=0;i<m_fiaSourceInfos.GetSize();i++)
            sf.WriteString("\""+m_fiaSourceInfos[i].GetFilePath() + "\"\n");
         sf.WriteString(_T("TARGET FILES:\n"));
         for (i=0;i<m_fiaTargetInfos.GetSize();i++)
            sf.WriteString("\"" + m_fiaTargetInfos[i].GetFilePath() + "\"\n");
         sf.WriteString(_T("MATCHED FILES:\n"));
         for (i=0;i<m_msaMatchedInfos.GetSize();i++) 
            sf.WriteString("\"" + m_msaMatchedInfos[i].pfinSource->GetFilePath() + "\"" + 
               " \\ " + "\"" + m_msaMatchedInfos[i].pfinTarget->GetFilePath() + "\"\n");
         sf.Close();
      } catch (CException e) {
         e.Delete();
      }

   }
}

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
Spain Spain
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions