=?windows-1252?Q?Re=3A_MFC_SDI_Application_without_a_default_=93New_Doc?=
=?windows-1252?Q?ument=94_on_Startup?=
On Apr 20, 7:20 am, Jd <j.durgapra...@gmail.com> wrote:
I have an SDI application with multiple views. By default, it creates
a new document when the application starts. I want to modify this
behavior so that a new document is created only when user explicitly
clicks on "New". Or at least mimic this behavior.
Try this, BUT! At your own peril. In your initInstance, locate
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(...
and replace it with the following:
class CDocTemplateXXX : public CSingleDocTemplate
{
public:
CDocTemplateXXX(
UINT nIDResource,
CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass,
CRuntimeClass* pViewClass)
: CSingleDocTemplate(nIDResource, pDocClass, pFrameClass,
pViewClass)
, m_bStartup(true)
{}
private:
virtual CDocument* OpenDocumentFile(
LPCTSTR lpszPathName,
BOOL bMakeVisible = TRUE)
{
CFrameWnd* pFrame = STATIC_DOWNCAST(CFrameWnd, AfxGetMainWnd());
if (!lpszPathName && m_bStartup)
{ // User started the app and we have no file to open -
// do our magic.
m_bStartup = false;
// We're about to create first ever frame here, so..
ASSERT(!AfxGetThread()->m_pMainWnd);
// Create frame.
CFrameWnd* pFrame = CreateNewFrame(NULL, NULL);
if (pFrame == NULL)
{ // Possible, but un-possible :-)
ASSERT(FALSE);
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
return NULL;
}
// Set main frame (MFC will look at this later to see if it's
// worth it to continue.
AfxGetThread()->m_pMainWnd = pFrame;
// Update main frame.
InitialUpdateFrame(pFrame, NULL, bMakeVisible);
return NULL;
}
m_bStartup = false;
// No magic => do what was in base class call, but take care of
the frame
CDocument* pDocument = NULL;
BOOL bCreated = FALSE; // => doc and frame created
BOOL bWasModified = FALSE;
if (m_pOnlyDoc != NULL)
{
// already have a document - reinit it
pDocument = m_pOnlyDoc;
if (!pDocument->SaveModified())
return NULL; // leave the original one
pFrame = (CFrameWnd*)AfxGetMainWnd();
ASSERT(pFrame != NULL);
ASSERT_KINDOF(CFrameWnd, pFrame);
ASSERT_VALID(pFrame);
}
else
{
// create a new document
pDocument = CreateNewDocument();
bCreated = TRUE;
}
if (pDocument == NULL)
{
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
return NULL;
}
ASSERT(pDocument == m_pOnlyDoc);
if (pFrame == NULL)
{
ASSERT(bCreated);
// create frame - set as main document frame
BOOL bAutoDelete = pDocument->m_bAutoDelete;
pDocument->m_bAutoDelete = FALSE;
// don't destroy if something goes wrong
pFrame = CreateNewFrame(pDocument, NULL);
pDocument->m_bAutoDelete = bAutoDelete;
if (pFrame == NULL)
{
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
delete pDocument; // explicit delete on error
return NULL;
}
}
if (lpszPathName == NULL)
{
// create a new document
SetDefaultTitle(pDocument);
// avoid creating temporary compound file when starting up
invisible
if (!bMakeVisible)
pDocument->m_bEmbedded = TRUE;
if (!pDocument->OnNewDocument())
{
// user has been alerted to what failed in OnNewDocument
TRACE(traceAppMsg, 0, "CDocument::OnNewDocument returned FALSE.
\n");
if (bCreated)
pFrame->DestroyWindow(); // will destroy document
return NULL;
}
}
else
{
CWaitCursor wait;
// open an existing document
bWasModified = pDocument->IsModified();
pDocument->SetModifiedFlag(FALSE); // not dirty for open
if (!pDocument->OnOpenDocument(lpszPathName))
{
// user has been alerted to what failed in OnOpenDocument
TRACE(traceAppMsg, 0, "CDocument::OnOpenDocument returned FALSE.
\n");
if (bCreated)
{
pFrame->DestroyWindow(); // will destroy document
}
else if (!pDocument->IsModified())
{
// original document is untouched
pDocument->SetModifiedFlag(bWasModified);
}
else
{
// we corrupted the original document
SetDefaultTitle(pDocument);
if (!pDocument->OnNewDocument())
{
TRACE(traceAppMsg, 0, "Error: OnNewDocument failed after
trying "
"to open a document - trying to continue.\n");
// assume we can continue
}
}
return NULL; // open failed
}
pDocument->SetPathName(lpszPathName);
}
CWinThread* pThread = AfxGetThread();
ASSERT(pThread);
if (bCreated && pThread->m_pMainWnd == NULL)
{
// set as main frame (InitialUpdateFrame will show the window)
pThread->m_pMainWnd = pFrame;
}
InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
return pDocument;
}
// True at startup.
// False after first call to OpenDocumentFile.
bool m_bStartup;
};
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CDocTemplateXXX(
IDR_MAINFRAME,
RUNTIME_CLASS(CFileNewDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CFileNewView));
if (!lpszPathName && m_bStartup) is the key: there, code creates a
frame with no document. The rest is copied from the base class. You
will need to change various ASSERTS that check the document for
validity. These are also inserted by wizard-generated code.
Is this a correct approach/design/choice in first place?
I would think not.
As usual with these situations, question is why do you think you want
any of this. Empty document is just as good as no document. And in one
respect, it's better: when your user starts your program, he doesn't
have to through an additional hoop of actually requesting a new one.
Why are you asking your users to work more? What do you think you are
buying by starting up with no document?
And finally, did you consider opening last-open document at startup?
That's a nice touch for certain situations. Visual Studio has that as
an option. That could mostly avoid whatever you are trying to avoid.
HTH,
Goran.