-
October 10th, 2013, 02:39 PM
#1
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
-
October 10th, 2013, 02:50 PM
#2
Re: Getting rid of 'Save changes to Untitled?'
Originally Posted by Mike Pliam
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.
-
October 11th, 2013, 03:07 AM
#3
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;
}
-
October 11th, 2013, 05:44 AM
#4
Re: Getting rid of 'Save changes to Untitled?'
Originally Posted by Mike Pliam
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
-
October 14th, 2013, 02:34 PM
#5
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
-
October 14th, 2013, 03:21 PM
#6
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
-
October 15th, 2013, 04:42 AM
#7
Re: Getting rid of 'Save changes to Untitled?'
Originally Posted by Mike Pliam
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
-
October 15th, 2013, 04:50 AM
#8
Re: Getting rid of 'Save changes to Untitled?'
Originally Posted by Mike Pliam
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
-
October 15th, 2013, 04:18 PM
#9
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
-
October 15th, 2013, 04:33 PM
#10
Re: Getting rid of 'Save changes to Untitled?'
Originally Posted by Mike Pliam
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.
-
October 15th, 2013, 04:34 PM
#11
Re: Getting rid of 'Save changes to Untitled?'
Originally Posted by Mike Pliam
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|