Custom MFC open save dialog box Extension

Source: Internet
Author: User
Document directory
  • Custom MFC open/save dialog box Extension
Custom MFC open/save dialog box Extension

The top project name here is d-trinet, and the document extension name is .dtnand .csv.

To enable the open/save dialog box to support multiple extensions, the simplest way is to modify the idr_dtrinettype field in the resource file:

STRINGTABLE BEGIN    IDR_MAINFRAME           "D-TriNet"    IDR_DTriNetTYPE         "\nDTriNet\nD-TriNet\nD-TriNet     Files(*.dtn;*.csv)\n.dtn;.csv\nDTriNet.Document\nD-TriNet.Document"END

The disadvantage is that files can have multiple extensions, but they are still divided into two categories: "D-Trinet Files" and "all files ". To classify data in more detail, you need to rewrite related virtual functions. The specific method is not unique. I think the better one is to rewrite cdocmanager: dopromptfilename.

The text below is a bit messy, because its content is organized according to my exploration process.

First, consider opening the dialog box. The first step is to find out when the dialog box is opened (where?

By default, cdtrinetapp calls the cwinapp: onfileopen method to process fileopen events:


Cwinapp: onfileopen and call cdocmanager: onfileopen to process fileopen events:

void CWinApp::OnFileOpen(){ENSURE(m_pDocManager != NULL);m_pDocManager->OnFileOpen();}

The cdocmanager: onfileopen display dialog box interacts with the user, and then calls the cwinapp: opendocumentfile method:

void CDocManager::OnFileOpen(){// prompt the user (with all document templates)CString newName;if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,  OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))return; // open cancelledAfxGetApp()->OpenDocumentFile(newName);// if returns NULL, the user has already been alerted}

Obviously, one possible solution is to bypass cwinapp and cdocmanager, display the custom dialog box in the cdtrinetapp: onfileopen method, and then call the cwinapp: opendocumentfile method.

On_command (id_file_open, & cdtrinetapp: onfileopen) void cdtrinetapp: onfileopen () {lpctstr szfilter = l "dtrinet file (*. dtn) | *. dtn | CSV file (*. CSV) | *. CSV | all files (*. *) | *. * | "; cfiledialog ofiledlg (true, l ". dtn ", null, 4 | 2, szfilter); If (ofiledlg. domodal () = idok) opendocumentfile (ofiledlg. getfilename (); // cdtrinetapp does not need to rewrite cwinapp: opendocumentfile method}

Now consider saving the dialog box. The first step is to find out when (where) the Save dialog box pops up?

When sending a message, the cdocument: dofilesave virtual method is called:

BOOL CDocument::DoFileSave(){DWORD dwAttrib = GetFileAttributes(m_strPathName);if (dwAttrib & FILE_ATTRIBUTE_READONLY){// we do not have read-write access or the file does not (now) existif (!DoSave(NULL)){TRACE(traceAppMsg, 0, "Warning: File save with new name failed.\n");return FALSE;}}else{if (!DoSave(m_strPathName)){TRACE(traceAppMsg, 0, "Warning: File save failed.\n");return FALSE;}}return TRUE;}

Cdocument: dofilesave call cdocument: dosave is also a virtual method :( Note: There is no dosaveas method, and the lpszpathname parameter determines the cdocument :: dosave is represented as "save" or "Save ".)

BOOL CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace)// Save the document data to a file// lpszPathName = path name where to save document file// if lpszPathName is NULL then the user will be prompted (SaveAs)// note: lpszPathName can be different than 'm_strPathName'// if 'bReplace' is TRUE will change file name if successful (SaveAs)// if 'bReplace' is FALSE will not change path name (SaveCopyAs){CString newName = lpszPathName;if (newName.IsEmpty()){CDocTemplate* pTemplate = GetDocTemplate();ASSERT(pTemplate != NULL);newName = m_strPathName;if (bReplace && newName.IsEmpty()){newName = m_strTitle;// check for dubious filenameint iBad = newName.FindOneOf(_T(":/\\"));if (iBad != -1)newName.ReleaseBuffer(iBad);// append the default suffix if there is oneCString strExt;if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) &&  !strExt.IsEmpty()){ASSERT(strExt[0] == '.');int iStart = 0;newName += strExt.Tokenize(_T(";"), iStart);}}if (!AfxGetApp()->DoPromptFileName(newName,  bReplace ? AFX_IDS_SAVEFILE : AFX_IDS_SAVEFILECOPY,  OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, FALSE, pTemplate))return FALSE;       // don't even attempt to save}CWaitCursor wait;if (!OnSaveDocument(newName)){if (lpszPathName == NULL){// be sure to delete the fileTRY{CFile::Remove(newName);}CATCH_ALL(e){TRACE(traceAppMsg, 0, "Warning: failed to delete file after failed SaveAs.\n");DELETE_EXCEPTION(e);}END_CATCH_ALL}return FALSE;}// reset the title and change the document nameif (bReplace)SetPathName(newName);return TRUE;        // success}

The cdocument: dosave virtual method calls the cwinapp: dopromptfilename method to bring up the Save dialog box. The latter then calls the cdocmanager: dopromptfilename virtual method (the case is the same as when the file is opened ):

BOOL CDocManager::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate){CFileDialog dlgFile(bOpenFileDialog, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, NULL, NULL, 0);CString title;VERIFY(title.LoadString(nIDSTitle));dlgFile.m_ofn.Flags |= lFlags;CString strFilter;CString strDefault;if (pTemplate != NULL){ASSERT_VALID(pTemplate);_AfxAppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, &strDefault);}else{// do for all doc templatePOSITION pos = m_templateList.GetHeadPosition();BOOL bFirst = TRUE;while (pos != NULL){pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);_AfxAppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate,bFirst ? &strDefault : NULL);bFirst = FALSE;}}// append the "*.*" all files filterCString allFilter;VERIFY(allFilter.LoadString(AFX_IDS_ALLFILTER));strFilter += allFilter;strFilter += (TCHAR)'\0';   // next string pleasestrFilter += _T("*.*");strFilter += (TCHAR)'\0';   // last stringdlgFile.m_ofn.nMaxCustFilter++;dlgFile.m_ofn.lpstrFilter = strFilter;dlgFile.m_ofn.lpstrTitle = title;dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);INT_PTR nResult = dlgFile.DoModal();fileName.ReleaseBuffer();return nResult == IDOK;}

It seems that the proportion of the override cdocmanager: dopromptfilename method to write the cdocument: dosave method should be easier:

Bool cdtrinetdocmgr: dopromptfilename (cstring & filename, uint nidstitle, DWORD lflags, bool bopenfiledialog, cdoctemplate * ptemplate) {lpctstr strfilter = l "dtrinet file (*. dtn) | *. dtn | CSV file (*. CSV) | *. CSV | all files (*. *) | *. * | "; cfiledialog dlgfile (bopenfiledialog, null, null, ofn_hidereadonly | ofn_overwriteprompt, strfilter, null, 0); cstring title; Verify (title. loadstring (nidstitle); dlgfile. m_ofn.lpstrtitle = title; dlgfile. m_ofn.lpstrfile = filename. getbuffer (_ max_path); int_ptr nresult = dlgfile. domodal (); filename. releasebuffer (); Return nresult = idok ;}

Cdtrinetdocmgr is a class derived from cdocmanager. The next question is: how to create a cdtrinetdocmgr object (instead of a cdocmanager object) for cwinapp: m_pdocmanager )? M_pdocmanager is created in the rewritten cwinapp: initinstance virtual method. Specifically, it is created in the cwinapp: adddoctemplate method. cwinapp :: the adddoctemplate method checks whether it is null before m_pdocmanager is created. The cdocmanager object is created only when m_pdocmanager is null. Therefore, you do not need to override the cwinapp: adddoctemplate method, instead, you only need to create the cdtrinetdocmgr object for m_pdocmanager In the rewritten cwinapp: initinstance method and before calling the cwinapp: adddoctemplate method.

Once the cdocmanager: dopromptfilename method is rewritten, the previously mentioned method for customizing the file extension of the open dialog box will be redundant, and the idr_dtrinettype field in the resource file will no longer need to be modified, because no matter whether the dialog box is opened or saved, it is finally executed by cdocmanager: dopromptfilename.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.