CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    Join Date
    May 2002
    Posts
    1,798

    Getting rid of 'Save changes to Untitled?'

    I have tried everything I can think of to get rid of the 'Save changes to Untitled?' message box that appears every time my SDI split app tries to load a new file. The problem is that the message appears inappropriately, both when no previous document has been loaded or should exist, and even after File / New has been envoked. I have attached a small demo program to demo the problem. Inspecting the SpVwTrDoc.cpp NewDocument and OnOpenDocument, and elsewhere, you will see that using SetModifiedFlag(FALSE); has no effect. The web is full of posts on this problem but nowhere can I find a solution. While the app still works, the message is annoying and for a client distributed app, it lends a distinct air of amateurism to the whole program. Any help greatly appreciated. Thanks.
    mpliam

  2. #2
    GCDEF is offline Elite Member Power Poster
    Join Date
    Nov 2003
    Location
    Florida
    Posts
    12,635

    Re: Getting rid of 'Save changes to Untitled?'

    Quote Originally Posted by Mike Pliam View Post
    I have tried everything I can think of to get rid of the 'Save changes to Untitled?' message box that appears every time my SDI split app tries to load a new file. The problem is that the message appears inappropriately, both when no previous document has been loaded or should exist, and even after File / New has been envoked. I have attached a small demo program to demo the problem. Inspecting the SpVwTrDoc.cpp NewDocument and OnOpenDocument, and elsewhere, you will see that using SetModifiedFlag(FALSE); has no effect. The web is full of posts on this problem but nowhere can I find a solution. While the app still works, the message is annoying and for a client distributed app, it lends a distinct air of amateurism to the whole program. Any help greatly appreciated. Thanks.
    I only have 2008 at home so I can't run it, but I would think your call stack should show you how you got there, and with that information you could take steps to stop it.

  3. #3
    Join Date
    Jan 2012
    Location
    India
    Posts
    193

    Re: Getting rid of 'Save changes to Untitled?'

    I faced the same problem ..
    I overrided SaveModified() Function ...

    This solved my problem ...

    BOOL CMyProgDoc::SaveModified()
    {

    if (!IsModified())
    return TRUE; // ok to continue

    // get name/title of document
    CString name;
    if (m_strPathName.IsEmpty()) {
    // get name based on caption
    name = m_strTitle;
    if (name.IsEmpty())
    VERIFY(name.LoadString(AFX_IDS_UNTITLED));
    }
    else {
    // get name based on file title of path name
    name = m_strPathName;
    }
    OnSaveDocument(name);
    return TRUE;
    }

  4. #4
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Getting rid of 'Save changes to Untitled?'

    Quote Originally Posted by Mike Pliam View Post
    The problem is that the message appears inappropriately, both when no previous document has been loaded or should exist, and even after File / New has been envoked. I have attached a small demo program to demo the problem. Inspecting the SpVwTrDoc.cpp NewDocument and OnOpenDocument, and elsewhere, you will see that using SetModifiedFlag(FALSE); has no effect. The web is full of posts on this problem but nowhere can I find a solution.
    This is where your problem is:
    Code:
    void CSpVwTrDoc::Serialize(CArchive& ar)
    {
        if (ar.IsStoring())
        {
            // TODO: add storing code here
        }
        else
        {
            // TODO: add loading code here
            //SetModifiedFlag(FALSE);   // APPCRASH if you do this here ???
            m_csPathname = ar.m_strFileName;
            //OnOpenDocument(m_csPathname);
            CDocManager * pDocMgr = (CDocManager *)AfxGetApp()->m_pDocManager;
            //pDocMgr->SaveAllModified();
            pDocMgr->OpenDocumentFile(m_csPathname);
    
        }
    }
    You are supposed to de-serialize your document, but on some reason you re-open your doc with doc manager. Being put to de-serialization, the document is marked as dirty, therefore, on opening it second time it asks you to save it before opening. Quite clever of MFC.

    Code:
    >    mfc100ud.dll!CDocManager::OpenDocumentFile(const wchar_t * lpszFileName, int bAddToMRU)  Line 1018    C++
         mfc100ud.dll!CDocManager::OpenDocumentFile(const wchar_t * lpszFileName)  Line 977    C++
         SpVwTr.exe!CSpVwTrDoc::Serialize(CArchive & ar)  Line 84 + 0x28 bytes    C++
         mfc100ud.dll!CDocument::OnOpenDocument(const wchar_t * lpszPathName)  Line 756    C++
         SpVwTr.exe!CSpVwTrDoc::OnOpenDocument(const wchar_t * lpszPathName)  Line 165 + 0xc bytes    C++
         mfc100ud.dll!CSingleDocTemplate::OpenDocumentFile(const wchar_t * lpszPathName, int bAddToMRU, int bMakeVisible)  Line 169 + 0x14 bytes    C++
         mfc100ud.dll!CDocManager::OpenDocumentFile(const wchar_t * lpszFileName, int bAddToMRU)  Line 1068    C++
         mfc100ud.dll!CDocManager::OpenDocumentFile(const wchar_t * lpszFileName)  Line 977    C++
         mfc100ud.dll!CWinApp::OpenDocumentFile(const wchar_t * lpszFileName)  Line 90    C++
         mfc100ud.dll!CDocManager::OnFileOpen()  Line 938    C++
         mfc100ud.dll!CWinApp::OnFileOpen()  Line 30    C++
         mfc100ud.dll!_AfxDispatchCmdMsg(CCmdTarget * pTarget, unsigned int nID, int nCode, void (void)* pfn, void * pExtra, unsigned int nSig, AFX_CMDHANDLERINFO * pHandlerInfo)  Line 82    C++
         mfc100ud.dll!CCmdTarget::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo)  Line 381 + 0x27 bytes    C++
         mfc100ud.dll!CFrameWnd::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo)  Line 978 + 0x23 bytes    C++
         mfc100ud.dll!CWnd::OnCommand(unsigned int wParam, long lParam)  Line 2729    C++
         mfc100ud.dll!CFrameWnd::OnCommand(unsigned int wParam, long lParam)  Line 371    C++
         mfc100ud.dll!CWnd::OnWndMsg(unsigned int message, unsigned int wParam, long lParam, long * pResult)  Line 2101 + 0x1e bytes    C++
         mfc100ud.dll!CWnd::WindowProc(unsigned int message, unsigned int wParam, long lParam)  Line 2087 + 0x20 bytes    C++
         mfc100ud.dll!AfxCallWndProc(CWnd * pWnd, HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam)  Line 257 + 0x1c bytes    C++
         mfc100ud.dll!AfxWndProc(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam)  Line 420    C++
         mfc100ud.dll!AfxWndProcBase(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam)  Line 420 + 0x15 bytes    C++
         user32.dll!76ed62fa()     
         [Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]    
         user32.dll!76ed6d3a()     
         user32.dll!76ed6ce9()     
         user32.dll!76ed965e()     
         user32.dll!76ed96c5()     
         comctl32.dll!74b16977()     
         comctl32.dll!74b169c3()     
         mfc100ud.dll!AfxLockGlobals(int nLockType)  Line 94    C++
         mfc100ud.dll!_afxResourceLock()  + 0xa8 bytes    C++
         cccc0004()
    Best regards,
    Igor

  5. #5
    Join Date
    May 2002
    Posts
    1,798

    Re: Getting rid of 'Save changes to Untitled?'

    Igor. Thanks once again. Your suggestion fixed the problem. When there is alot of processing to do to open a document (which might be anything from a text file to a complex database or more), the processing can be done in the OnOpenDocument method provide one has captured the ar->m_strFilename and set it as a member path, i.e., m_csPathname and ignoring the OnOpenDocument input parameter. I get that part. But I do not understand how simply by invoking

    Code:
    CDocManager * pDocMgr = (CDocManager *)AfxGetApp()->m_pDocManager;
    in the document serialization loading code, the whole process gets loaded. I guess it must all be built into the API since it works beautifully, even the MRU files load as they should without alot of extra coding, but it's certainly not obvious. There is an enormous amount of information available to read about serialization - too much for me to digest. Sometimes just a few words of explanation is best.

    Unfortunately, the Serialize ar.IsStoring code doesnt work symmetrically. Using the same basic scheme as you have outlined above for loading, the OnSaveDocument is processed BEFORE the Serialize::ar.IsStoring so that there is no easy way to get hold of the pathname. Obviously, there are many possible work-arounds, but they mainly involve overriding OnFileSave. Seems odd to me.

    I am curious about how you obtained such a nice printout of the stack? Mine never looks quite as thorough.

    FWIW, the member code above crashes my app.
    Last edited by Mike Pliam; October 14th, 2013 at 03:05 PM.
    mpliam

  6. #6
    Join Date
    May 2002
    Posts
    1,798

    Re: Getting rid of 'Save changes to Untitled?'

    After reexamining my code, it appears that it is not necessary to use ::Serialize at all. Simply override OnOpenDocument and OnSaveDocument and the required path name magically appears as the input parameter in each case. And the MRU Files menu also works. SO WHY USE ::Serialize ???
    mpliam

  7. #7
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Getting rid of 'Save changes to Untitled?'

    Quote Originally Posted by Mike Pliam View Post
    But I do not understand how simply by invoking

    Code:
    CDocManager * pDocMgr = (CDocManager *)AfxGetApp()->m_pDocManager;
    in the document serialization loading code, the whole process gets loaded.
    As I said, you are not supposed to call doc manager in Serialize. In Serialize you do serialization of all your essential data, i.e. you deal with the document itself.

    See what it looks like from document's perspective:
    Code:
    BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName)
    {
    	ENSURE(lpszPathName);
    
    	CFileException *pfe = new CFileException;
    	CFile* pFile = NULL;
    	pFile = GetFile(lpszPathName, CFile::modeCreate |
    		CFile::modeReadWrite | CFile::shareExclusive, pfe);
    
    	if (pFile == NULL)
    	{
    		TRY
    		{
    			ReportSaveLoadException(lpszPathName, pfe,
    				TRUE, AFX_IDP_INVALID_FILENAME);
    		}
    		END_TRY
    		DELETE_EXCEPTION(pfe);
    		return FALSE;
    	}
    
    	DELETE_EXCEPTION(pfe);
    
    	CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete);
    	saveArchive.m_pDocument = this;
    	saveArchive.m_bForceFlat = FALSE;
    	TRY
    	{
    		CWaitCursor wait;
    		Serialize(saveArchive);     // save me
    		saveArchive.Close();
    		ReleaseFile(pFile, FALSE);
    	}
    	CATCH_ALL(e)
    	{
    		ReleaseFile(pFile, TRUE);
    
    		TRY
    		{
    			ReportSaveLoadException(lpszPathName, e,
    				TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
    		}
    		END_TRY
    		DELETE_EXCEPTION(e);
    		return FALSE;
    	}
    	END_CATCH_ALL
    
    	SetModifiedFlag(FALSE);     // back to unmodified
    
    	return TRUE;        // success
    }
    So, this all looks like document is set to archive, archive object is passed for serialization, Serialize writes the data to archive (which ends up in fact in the previously opened file), archive gets closed on end of serialization, and finally file gets closed too. There's nothing to manage here, as the whole process is rather straightforward.

    I guess it must all be built into the API since it works beautifully, even the MRU files load as they should without alot of extra coding, but it's certainly not obvious. There is an enormous amount of information available to read about serialization - too much for me to digest. Sometimes just a few words of explanation is best.
    Serialization in MFC
    Storing and Loading CObjects via an Archive
    From MSDN:
    If you want, you can bypass MFC serialization to create your own mechanism for persistent data storage. You will need to override the class member functions that initiate serialization at the user's command. See the discussion in Technical Note 22 of the ID_FILE_OPEN, ID_FILE_SAVE, and ID_FILE_SAVE_AS standard commands.
    Unfortunately, the Serialize ar.IsStoring code doesnt work symmetrically. Using the same basic scheme as you have outlined above for loading, the OnSaveDocument is processed BEFORE the Serialize::ar.IsStoring so that there is no easy way to get hold of the pathname. Obviously, there are many possible work-arounds, but they mainly involve overriding OnFileSave. Seems odd to me.
    Nothing odd there. OnSaveDocument is what it says:
    The default implementation of this function opens the specified file, calls CObject::Serialize to write the document's data to the file, and then marks the document as clean. Override this function if you want to perform special processing when the framework saves a document. For example, you might write an application where documents represent records in a database rather than separate files.
    You override OnSaveDocument either to do some preparations prior to saving document standard way (CDocument::OnSaveDocument), or to implement your custom saving data. Everything is neat and clear, as for me.

    I am curious about how you obtained such a nice printout of the stack? Mine never looks quite as thorough.
    Go to Call Stack pane, select all with Ctrl+A, copy to clipboard with Ctrl+C. End of story.
    Best regards,
    Igor

  8. #8
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Getting rid of 'Save changes to Untitled?'

    Quote Originally Posted by Mike Pliam View Post
    SO WHY USE ::Serialize ???
    Your data objects may be implemented serializing themselves. So document serialization looks like just iteration through a list of objects comprising the "document," and making them serialize to the provided archive. Object-oriented approach, you know...
    Best regards,
    Igor

  9. #9
    Join Date
    May 2002
    Posts
    1,798

    Re: Getting rid of 'Save changes to Untitled?'

    If you want, you can bypass MFC serialization to create your own mechanism for persistent data storage. You will need to override the class member functions that initiate serialization at the user's command. See the discussion in Technical Note 22 of the ID_FILE_OPEN, ID_FILE_SAVE, and ID_FILE_SAVE_AS standard commands.
    I have completely bypassed ::Serialize and simply overridden OnOpenDocument and OnCloseDocument and things seem to be working ok. I did not override OnFileOpen, OnFileSave, or OnFileSaveAs since there appears to be no need to do so. I have read and reread the material on Serialization and am more confused than ever. I understand that serialization can be used for 'persistent storage' of class objects, and I assume that since serialization employs CFILE and CArchive, that the persistent storage is intended to be to disk and not to memory, but how is that useful? I can easily store and retrieve my important class variables in many ways other than using serialization (which I'm still not sure how to do anyway). Sorry to be so thick. You've done a courageous job of trying to help, but I'm afraid I still don't really get it. Thanks for all the time an trouble you've put into this thread (and many others).
    mpliam

  10. #10
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Getting rid of 'Save changes to Untitled?'

    Quote Originally Posted by Mike Pliam View Post
    I understand that serialization can be used for 'persistent storage' of class objects, and I assume that since serialization employs CFILE and CArchive, that the persistent storage is intended to be to disk and not to memory, but how is that useful? I can easily store and retrieve my important class variables in many ways other than using serialization (which I'm still not sure how to do anyway).
    It's useful because many times you want to close the program, reopen the program and be able to continue editing some work. Without persistent storage of some kind, a user would have to start over with a doc.

    Back when MFC was first created, it was a big help to have a framework that helped you persist data to disk. With MFC's serialization, it stores data in a binary format, has overloaded extraction operators (<<, >>), versioning and some other features, but because it stores the data in binary, it's harder to share the format with other applications. You also had to be careful about versioning the binary formats so you could read older files and update them with newer files.

    Storing info in this manner has kind of gone by the way side as there are many data formats/approaches available for persistent storage.

    If you want to learn about MFC's serialization, I would suggest trying to find an old 'Scribble' tutorial (and hopefully it will run with VS2008 or VS2012). It takes you through the concepts of serialization nicely.

    Of course, as I've said, you probably don't want to store data like this anyway, since there are other, more modern options.

  11. #11
    GCDEF is offline Elite Member Power Poster
    Join Date
    Nov 2003
    Location
    Florida
    Posts
    12,635

    Re: Getting rid of 'Save changes to Untitled?'

    Quote Originally Posted by Mike Pliam View Post
    I have completely bypassed ::Serialize and simply overridden OnOpenDocument and OnCloseDocument and things seem to be working ok. I did not override OnFileOpen, OnFileSave, or OnFileSaveAs since there appears to be no need to do so. I have read and reread the material on Serialization and am more confused than ever. I understand that serialization can be used for 'persistent storage' of class objects, and I assume that since serialization employs CFILE and CArchive, that the persistent storage is intended to be to disk and not to memory, but how is that useful? I can easily store and retrieve my important class variables in many ways other than using serialization (which I'm still not sure how to do anyway). Sorry to be so thick. You've done a courageous job of trying to help, but I'm afraid I still don't really get it. Thanks for all the time an trouble you've put into this thread (and many others).
    The biggest advantage to serialization other than it's really easy to implement, is that it maintains relationships among objects. So if you have a list of objects than point to other objects that have maps to other objects, etc. and you serialize and then restore it, that whole big structure comes back in, exactly as it was when you saved it out.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured