Custom Open File or Save as Dialog

My COpenFileDlg class is an Open or Save dialog that does not allow the user to navigate to any other directory and it only shows files of one specific extension.

Sometimes we don't want to allow the user to switch to another directory or we only need to bring up files of a desired type. COpenFileDlg will pop up a message if the directory doesn't exist and then calls CDialog::OnCancel. Remember the purpose is to restrict access to the user so that's why if the directory doesn't exist we don't want to create it.

Here is how you use the COpenFileDlg class

(1) Include the dialog resource in your project IDD_OPEN_FILE

(2) Insert COpenFileDlg.h and COpenFileDlg.cpp to your project.

(3) Instantiate the class passing to the constructor the following 4 parameters:

The directory path

The file extension(not a wild card, just the extension)

The resource id of an icon that you want to represent the files with (Don't forget to use the appropiate icon size (16X16))

Either TRUE(default) for Open File Dialog or FALSE for Save as Dialog.

(4) Call DoModal on the Instance of COpenFileDlg.

(5) Call either of the two public member functions.

GetFileName() returns only the file name.

GetFilePath() return the full path.

(6) Look at the source code for details.

You'll notice that the dialog resource has a hidden listbox that I use only to forward the file names to the list control since the list control lacks this funcionality. You can click on a file name to select it or double click to select and dismiss the dialog.

Thanks for the time you've taken to read my article and feel free to email me your suggestions.


#include "OpenFileDlg.h"

void CCustomOpenFileDlg::OnShowCustomOpenFileDlg() 
{
 COpenFileDlg dlg(m_strDirPath, m_strFileExt, IDI_FILE_ICON);
 dlg.DoModal();
}

void CCustomOpenFileDlg::OnShowCustomSaveAsFileDlg() 
{
 COpenFileDlg dlg(m_strDirPath, m_strFileExt, IDI_FILE_ICON, FALSE);
 dlg.DoModal();
}

/////////////////////////////////////////////////////////////////////////////
// COpenFileDlg message handlers

BOOL COpenFileDlg::OnInitDialog() 
{
 CDialog::OnInitDialog();

 CWnd* pWnd;
 CString strWndTitle;

 if (!m_bIsOpenFileDlg)
 {
  strWndTitle.LoadString(_T(IDS_SAVE_FILE_AS));
  SetWindowText(strWndTitle);
  SetDlgItemText(IDOK, "Save");
 }
 else
 {
  strWndTitle.LoadString(_T(IDS_OPEN_FILE));
  SetWindowText(strWndTitle);
 }

 pWnd = GetDlgItem(IDOK);
 pWnd->EnableWindow(FALSE);

 CFileFind fileFind;

 // If directory does not exist, do not waste time
 if (!fileFind.FindFile(m_strDir))
 {
  CString msg("");
  msg.Format("Directory %s does not exist", m_strDir);
  MessageBox(msg, "Custom Open File Dialog", MB_OK | MB_ICONWARNING); 
  CDialog::OnCancel();
 }
	
 CString pathAndFileType = m_strDir + "\\*." + m_strFileType;
 m_ctrlFiles.Dir(DDL_DIRECTORY, pathAndFileType);

 int rowCount = m_ctrlFiles.GetCount();
 int row = m_ctrlFiles.GetTopIndex();

 m_IconImage.Create(::GetSystemMetrics(SM_CXICON) / 2,
  ::GetSystemMetrics(SM_CYICON) / 2, TRUE, 10, 10);

 m_IconImage.Add( AfxGetApp()->LoadIcon(m_nIconId) );
 m_ctrlRequestedFiles.SetImageList(&m_IconImage, LVSIL_SMALL);

 LV_ITEM item;   // Create the list items
 item.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
 item.state = item.stateMask = 0;

 // Iterate through the items in the listbox and populate the listconrol.
 CString strBuffer;
 for (row; row < rowCount; row++)
 {
  item.iItem = row; 
  item.iSubItem = 0; // refers to item therefore  = 0

  m_ctrlFiles.GetText(row, strBuffer);

  item.pszText = (char*) (LPCTSTR) strBuffer;
  item.iImage  = 0;

  item.lParam = row;
  m_ctrlRequestedFiles.InsertItem(&item);
 }
	
 return TRUE;  // return TRUE unless you set the focus to a control
 // EXCEPTION: OCX Property Pages should return FALSE
}

void COpenFileDlg::OnOK() 
{
 int index = m_ctrlRequestedFiles.GetNextItem(-1, LVNI_SELECTED);

 if (index > -1)
 {
  m_strFileName = m_ctrlRequestedFiles.GetItemText(index, 0);
 }
 else
 {
  m_ctrlFileName.GetWindowText(m_strFileName);

  CString strExt = "." + m_strFileType;

  if (!m_strFileName.IsEmpty())
  {
   int nFoundExt = m_strFileName.Find(strExt);

   if (nFoundExt < 0)
   {
    m_strFileName += strExt;
   }
  }
 }

 CDialog::OnOK();
}

void COpenFileDlg::OnClickRequestedFiles(NMHDR* pNMHDR, LRESULT* pResult) 
{
 int index = m_ctrlRequestedFiles.GetNextItem(-1, LVNI_SELECTED);

 if (index > -1)
 {
  m_strFileName = m_ctrlRequestedFiles.GetItemText(index, 0);

  m_ctrlFileName.SetWindowText(m_strFileName);
 }
 else
 {
  m_ctrlFileName.GetWindowText(m_strFileName);
		
  if ( m_strFileName.IsEmpty() )
  {
   CWnd* pWnd = GetDlgItem(IDOK);
   pWnd->EnableWindow(FALSE);
  }
 }
	
 *pResult = 0;
}

void COpenFileDlg::OnDblclkRequestedFiles(NMHDR* pNMHDR, LRESULT* pResult) 
{
 int index = m_ctrlRequestedFiles.GetNextItem(-1, LVNI_SELECTED);

 if (index > -1)
 {
  m_strFileName = m_ctrlRequestedFiles.GetItemText(index, 0);
 }

 CDialog::OnOK();

 *pResult = 0;
}

void COpenFileDlg::OnUpdateEditFilename() 
{
 // TODO: If this is a RICHEDIT control, the control will not
 // send this notification unless you override the CDialog::OnInitDialog()
 // function to send the EM_SETEVENTMASK message to the control
 // with the ENM_UPDATE flag ORed into the lParam mask.

 m_ctrlFileName.GetWindowText(m_strFileName);
		
 if ( m_strFileName.IsEmpty() )
 {
  CWnd* pWnd = GetDlgItem(IDOK);
  pWnd->EnableWindow(FALSE);
 }
 else
 {
  CWnd* pWnd = GetDlgItem(IDOK);
  pWnd->EnableWindow(TRUE);
 }
}

CString COpenFileDlg::GetFileName()
{
 return m_strFileName;
}

CString COpenFileDlg::GetFilePath()
{
 return m_strDir + "\\" + m_strFileName;
}

Download demo project - 7 KB

Download source - 18 KB

Date Last Updated: February 2, 1999