Manipulating the File Open/Save Filters

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

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++;
 }
}


Comments

  • Document File creation Problem with NT\2000

    Posted by Legacy on 03/12/2002 12:00am

    Originally posted by: SaiSrinivas.L.N.Achanta

    Hi
    I have a problem in VC++6.0.
    I have made a ActiveX control which is a MDI application.(an MDI application is turned into an ActiveX).It works fine in Win98.But it fails in NT\2000.
    The error is at OpenDocumentFile() function of CDocTemplate object.If I pass a valid pathname in that it woks fine in win98 but fails in NT/2000.
    Could U give me any solution for that?

    Regards
    SaiSrinivas

    Reply
  • Problem with CEditView

    Posted by Legacy on 01/24/2001 12:00am

    Originally posted by: Rajasekhar

    Hello!

    I am developing an application in eVC 3.0 using document/view(SDI) architecture.My main view is CView.It's working fine.I have one more screen with base calss as CEditView.It's working fine to write something and to save.But when i tried to open a file, after selecting the file name, this view getting disappeared and the main view is coming up.How to keep the CEditView as the top view until i want.I am not implementing the Open Dialog functionality.

    One more problem is, How to get the text i typed in the CEditView in to a string, because i want to save it to the database, and how to set some data in the CString to the CEditView.

    When i implemented the Open Dialog functionality it's not showing the files available in a directory.What might be the problem?

    Please help me in this regard.

    Please send mail to chavasekhar@rediffmail.com

    Thanking you,

    Rajasekhar

    Reply
  • Problems with SDI

    Posted by Legacy on 12/11/2000 12:00am

    Originally posted by: Michael B. Pliam

    I have been trying to set up a SDI app with multiple views and docs that will allow the user to Open and Save the different file types by opening the droplist on the Open/Save dialogs and selecting the file type. Something similar to Word97 would do nicely.

    I tried the approach you have suggested, realizing that your code was written for MDI apps.

    Unfortunately, even though I finally got the code to compile, I encountered an immediate CWinApp assertion violation.

    ASSERT(AfxGetThread() == NULL);

    I believe there must be a way to accomplish my goal as stated. Does anyone have any suggestions.

    Thanks

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date