Manipulating the File Open/Save Filters 

 

This article addresses 2 issues 

Removing *.* filter from the MFC Doc-View architecture Open/Save File dialogs 

Displaying only selected filters in the MFC Doc-View architecture Open/Save File dialogs 

The MFC Doc-View architectures "Open/Save File" functionality allows the user to open/save file of any type using the *.* filter. Now if you don't want the user to do this 

For example, I have created an MDI application using the AppWizard and I have the following 2 document templates - 

CDocTemplate *m_pTest1DocTemplate, m_pTest2DocTemplate

m_pTest1DocTemplate = new CMultiDocTemplate(IDR_TEST1TYPE, 

 RUNTIME_CLASS(CTest1Doc),

 RUNTIME_CLASS(CChildFrame), // custom MDI child frame

 RUNTIME_CLASS(CTest1View));

AddDocTemplate(m_pTest1DocTemplate);

m_pTest2DocTemplate = new CMultiDocTemplate(IDR_TEST2TYPE, 

 RUNTIME_CLASS(CTest2Doc),

 RUNTIME_CLASS(CChildFrame), // custom MDI child frame

 RUNTIME_CLASS(CTest2View));

AddDocTemplate(m_pTest2DocTemplate);

where...

IDR_TEST1TYPE = \nTest1\Test1 File\nTest1 Files(*.ts1)\n.ts1\nts1\nTest1\n

IDR_TEST2TYPE = \nTest2\Test2 File\nTest2 Files(*.ts2)\n.ts2\nts2\nTest2\n 

You have created a new Test1 file and added data to it. Now when you want to save the file and click on the save button. The save file dialog comes up and you can give a name to the file and save it. The tricky part is that this allows the file to be saved in to any extension and WE DID NOT WANT THIS. So to remove this *.* filter in the file types combo box I suggest the following - 

Derive a class CMyDocManager from CDocManager 

Provide a implentation of the virtual function DoPromptFileName which is defined in the CDocManager base class 

//Implementation of the base class virtual function

BOOL CCGPDocManager::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate)

{

 CString cstrInitialDir = ""; 

 //Depending on the Template you can set the Initial Folder 

 if(pTemplate == g_theApp.m_pTest1DocTemplate)

 {

  cstrInitialDir = "c:\\Test\\Test1Files";

 }

 else if(pTemplate == g_theApp.m_pTest2DocTemplate)

 {

  cstrInitialDir = "c:\\Test\\Test2Files";

 }

 return CUtility::DoPromptFileName(cstrInitialDir, fileName, nIDSTitle, lFlags, bOpenFileDialog, pTemplate);

}

In the InitApplication() function of your Application class add the following line - 

//m_pDocManager is already defined in the CWinApp class

m_pDocManager = new CCGPDocManager();

Now when the user tries to save a Test1 file then the user can only save it to a .ts1 extension 

To display only selected filters in the MFC Doc-View architecture Open File dialog 

Implement the OnFileOpen function in the CMainFrame class ON_COMMAND(ID_FILE_OPEN, OnFileOpen) 

void CMainFrame::OnFileOpen() 

{

 CString cstrFileName;

 CDocTemplate *paDocTemplate[] = {g_theApp.m_pTest1DocTemplate, 

  g_theApp.m_pTest2DocTemplate, 

  NULL};

 if(!CUtility::DoPromptFileName("", cstrFileName, AFX_IDS_OPENFILE, 

  OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, TRUE, 

  paDocTemplate))

   return;

 OpenDocumentFile(cstrFileName);

}

CUtility class

static BOOL DoPromptFileName(CString cstrInitialDir, CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate **pTemplate);

static BOOL DoPromptFileName(CString cstrInitialDir, CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate);

static void AppendFilterSuffix(CString& filter, OPENFILENAME& ofn, CDocTemplate* pTemplate, CString* pstrDefaultExt);

BOOL CUtility::DoPromptFileName(CString cstrInitialDir, CString& fileName, 

 UINT nIDSTitle, DWORD lFlags, 

 BOOL bOpenFileDialog, 

 CDocTemplate* pTemplate)

{

 CFileDialog dlgFile(bOpenFileDialog);

 CString title;

 VERIFY(title.LoadString(nIDSTitle));

 dlgFile.m_ofn.Flags |= lFlags;

 CString strFilter;

 CString strDefault;

 if(pTemplate != NULL)

 {

  ASSERT_VALID(pTemplate);

  AppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, &strDefault);

 }

 dlgFile.m_ofn.lpstrFilter = strFilter;

#ifndef _MAC

 dlgFile.m_ofn.lpstrTitle = title;

#else

 dlgFile.m_ofn.lpstrPrompt = title;

#endif

 dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);

 dlgFile.m_ofn.lpstrInitialDir = cstrInitialDir;

 BOOL bResult = dlgFile.DoModal() == IDOK ? TRUE : FALSE;

 fileName.ReleaseBuffer();

 CString strFilterExt;

 //Get the file extension of the template

 pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt);

 //Get the file extension of the selected file

 CString cstrSelFileExt = fileName.Right(fileName.GetLength() - fileName.ReverseFind('.'));

 cstrSelFileExt.MakeLower();

 strFilterExt.MakeLower();

 //compare both if not the same extension then return false

 if(strFilterExt.Find(cstrSelFileExt) == -1)

 {

  AfxMessageBox("Invalid extension", MB_OK | MB_ICONHAND);

  return FALSE;

 }

 return bResult;

}

BOOL CUtility::DoPromptFileName(CString cstrInitialDir, CString& fileName, 

 UINT nIDSTitle, DWORD lFlags, 

 BOOL bOpenFileDialog, 

 CDocTemplate **pTemplate)

{

 CFileDialog dlgFile(bOpenFileDialog);

 

 CString title;

 VERIFY(title.LoadString(nIDSTitle));

 dlgFile.m_ofn.Flags |= lFlags;

 CString strFilter;

 CString strDefault;

 int i = 0;

 while(pTemplate[i] != NULL)

 {

  ASSERT_VALID(pTemplate[i]);

  AppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate[i], &strDefault);

  i++;

 }

 

 dlgFile.m_ofn.lpstrFilter = strFilter;

#ifndef _MAC

 dlgFile.m_ofn.lpstrTitle = title;

#else

 dlgFile.m_ofn.lpstrPrompt = title;

#endif

 dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);

 dlgFile.m_ofn.lpstrInitialDir = cstrInitialDir;

 BOOL bResult = dlgFile.DoModal() == IDOK ? TRUE : FALSE;

 fileName.ReleaseBuffer();

 BOOL bExtMatched = FALSE;

 i = 0;

 while(pTemplate[i] != NULL)

 {

  CString strFilterExt;

  //Get the file extension of the template

  pTemplate[i]->GetDocString(strFilterExt, CDocTemplate::filterExt);

  //Get the file extension of the selected file

  CString cstrSelFileExt = fileName.Right(fileName.GetLength() - fileName.ReverseFind('.'));

  cstrSelFileExt.MakeLower();

  strFilterExt.MakeLower();

  if(strFilterExt.Find(cstrSelFileExt) != -1)

  {

   bExtMatched = TRUE;

   break;

  }

  i++;

 }

 if(!bExtMatched)

 {

  AfxMessageBox("Invalid extension", MB_OK | MB_ICONHAND);

  return FALSE;

 }

 return bResult;

}

void CUtility::AppendFilterSuffix(CString& filter, OPENFILENAME& ofn,

CDocTemplate* pTemplate, CString* pstrDefaultExt)

{

 ASSERT_VALID(pTemplate);

 ASSERT_KINDOF(CDocTemplate, pTemplate);

 CString strFilterExt, strFilterName;

 if (pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt) &&

 ! strFilterExt.IsEmpty() &&

 pTemplate->GetDocString(strFilterName, CDocTemplate::filterName) &&

 ! strFilterName.IsEmpty())

 {

  // a file based document template - add to filter list

#ifndef _MAC

  ASSERT(strFilterExt[0] == '.');

#endif

  if (pstrDefaultExt != NULL)

  {

   // set the default extension

#ifndef _MAC

   *pstrDefaultExt = ((LPCTSTR)strFilterExt) + 1;  // skip the '.'

#else

   *pstrDefaultExt = strFilterExt;

#endif

   ofn.lpstrDefExt = (LPTSTR)(LPCTSTR)(*pstrDefaultExt);

   ofn.nFilterIndex = ofn.nMaxCustFilter + 1;  // 1 based number

  }

  // add to filter

  filter += strFilterName;

  ASSERT(!filter.IsEmpty());  // must have a file type name

  filter += (TCHAR)'\0';  // next string please

#ifndef _MAC

  filter += (TCHAR)'*';

#endif

  filter += strFilterExt;

  filter += (TCHAR)'\0';  // next string please

  ofn.nMaxCustFilter++;

 }

}