Figure 1 Modified Scribble
scribble.h
////////////////////////////////////////////////////////////////
// Modified SCRIBBLE Copyright 1996 Microsoft Systems Journal.
// Portions Copyright (C) 1992-1995 Microsoft Corporation.
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// See SCRIBBLE.CPP for Description of program.
//
#include "resource.h" // main symbols
class CScribbleApp : public CWinApp {
public:
CScribbleApp();
~CScribbleApp();
virtual BOOL InitInstance();
// ***PD Override exception handler
virtual LRESULT ProcessWndProcException(CException* e, const MSG* pMsg);
//{{AFX_MSG(CScribbleApp)
afx_msg void OnAppAbout();
afx_msg void OnMyFileNew(); // ***PD: This replaces OnFileNew to
// handle ID_FILE_NEW
afx_msg void OnExUser();
afx_msg void OnExMemory();
afx_msg void OnExResource();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
scribble.cpp
////////////////////////////////////////////////////////////////
// Modified SCRIBBLE Copyright 1996 Microsoft Systems Journal.
// Portions Copyright (C) 1992-1995 Microsoft Corporation
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// This program is based on the SCRIBBLE program that comes with
// Microsoft Visual C++, as part of the MFC tutorial.
//
// This modified SCRIBBLE shows
//
// -how to write an SDI app that starts with an empty frame instead
// of a new document;
//
// -how to write an exception handler to handle any uncaught exception
// that occurs while the app is running.
//
// Mods identified with ***PD
//
#include "stdafx.h"
#include "Scribble.h"
#include "MainFrm.h"
#include "ScribDoc.h"
#include "ScribVw.h"
#include <eh.h> // set_terminate
#include "TraceWin.h"
BEGIN_MESSAGE_MAP(CScribbleApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
ON_COMMAND(ID_EX_USER, OnExUser)
ON_COMMAND(ID_EX_MEMORY, OnExMemory)
ON_COMMAND(ID_EX_RESOURCE, OnExResource)
ON_COMMAND(ID_FILE_NEW, OnMyFileNew) // ***PD: my own handler
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
CScribbleApp theApp;
typedef void (*TERMINATE_FN)();
TERMINATE_FN old_terminate = NULL;
////////////////
// Custom terminate handler just displays message
//
void my_terminate()
{
MessageBox(NULL, "Help me, I'm dying.", "Terminate", MB_OK);
// Call old terminate fn, if any. On Windows, old_terminate is NULL;
if (old_terminate)
old_terminate();
}
CScribbleApp::CScribbleApp()
{
MfxTraceInit(); // initialize TRACEWIN tracing
old_terminate = set_terminate(my_terminate);
TRACE("old terminate fn = %p\n", old_terminate);
}
CScribbleApp::~CScribbleApp()
{
set_terminate(old_terminate);
}
BOOL CScribbleApp::InitInstance()
{
SetRegistryKey("MSJ"); // Use HKEY_CURRENT_USER\Software\MSJ for INI
LoadStdProfileSettings(); // Load INI file options (including MRU file)
// create doc template
CDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CScribbleDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CScribbleView));
AddDocTemplate(pDocTemplate);
// EnableShellOpen(); // Only need for File Manager double-click/DDE
RegisterShellFileTypes(TRUE); // TRUE for Win 95
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (!ProcessShellCommand(cmdInfo)) // dispatch command
return FALSE;
return TRUE;
}
//////////////////
// ***PD REALLY create new document: initialize the empty doc object.
//
void CScribbleApp::OnMyFileNew()
{
OnFileNew(); // do normal thing to create new doc
// (in case this is an open doc, reuse it)
CFrameWnd* pFrame = (CFrameWnd*)m_pMainWnd;
ASSERT_KINDOF(CFrameWnd, pFrame);
CScribbleView* pView = (CScribbleView*)pFrame->GetActiveView();
ASSERT_KINDOF(CScribbleView, pView);
pView->GetDocument()->Initialize(); // initialize new doc
}
void CScribbleApp::OnAppAbout()
{
CDialog(IDD_ABOUTBOX).DoModal();
}
//////////////////
// Commands to throw various kinds of exceptions.
//
void CScribbleApp::OnExUser() { AfxThrowUserException(); }
void CScribbleApp::OnExMemory() { AfxThrowMemoryException(); }
void CScribbleApp::OnExResource() { AfxThrowResourceException(); }
//////////////////
// Exception handler of last resort. Display message box describing
// exception, then try to save all files.
//
LRESULT CScribbleApp::ProcessWndProcException(CException* e, const MSG* pMsg)
{
CString s = "An unhandled error occurred in your program.\n\n";
CString m;
m.Format("type\t%s\n", e->GetRuntimeClass()->m_lpszClassName);
s += m;
m.Format("HWND\t0x%04x\nmsg\t0x%04x\nwParam\t0x%08x\nlParam\t0x%08x",
pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
s += m;
s += "\n\nSelect:\nAbort \tto terminate the program;\n";
s += "Retry \tto let MFC handle the error; or\n";
s += "Ignore \tto do nothing.\n\n";
s += "After this dialog, you'll have a chance to save modified documents.";
int nRes = MessageBox(m_pMainWnd->GetSafeHwnd(), s, "Error!",
MB_ABORTRETRYIGNORE);
// Save any modified docs
SaveAllModified();
if (nRes==IDABORT)
THROW_LAST(); // will call terminate()
else if (nRes==IDRETRY)
return CWinApp::ProcessWndProcException(e, pMsg); // do MFC Thing
return 0; // IDIGNORE
}
scribdoc.h
////////////////////////////////////////////////////////////////
// Modified SCRIBBLE Copyright 1996 Microsoft Systems Journal.
// Portions Copyright (C) 1992-1995 Microsoft Corporation.
// NOTE: Only changes from original SCRIBBLE code are shown.
// Full source available on any MSJ bulletin board.
class CScribbleDoc : public CDocument {
protected:
BOOL m_bInitialized; // ***PD: whether doc is initialized
public:
.
.
.
void InitDocument();
// ***PD new functions
BOOL Initialize();
BOOL IsInitialized() { return m_bInitialized; }
.
.
.
};
scribdoc.cpp
////////////////////////////////////////////////////////////////
// Modified SCRIBBLE Copyright 1996 Microsoft Systems Journal.
// Portions Copyright (C) 1992-1995 Microsoft Corporation.
// NOTE: Only changes from original SCRIBBLE code are shown.
// Full source available on any MSJ bulletin board.
//
#include "stdafx.h"
#include "Scribble.h"
#include "ScribDoc.h"
.
.
.
BOOL CScribbleDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
InitDocument();
m_bInitialized = FALSE; // ***PD: Not initialized yet
return TRUE;
}
BOOL CScribbleDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
InitDocument();
return m_bInitialized = TRUE; // ***PD: an open doc is initialized
}
void CScribbleDoc::DeleteContents()
{
while (!m_strokeList.IsEmpty()) {
delete m_strokeList.RemoveHead();
}
CDocument::DeleteContents();
}
//////////////////
// ***PD: NOTE: This is the old function from the tutorial code. It's called
// InitDocument but it's only the raw initialization, not the
// "real" initialization, which requires setting m_bInitialized to TRUE.
//
void CScribbleDoc::InitDocument()
{
m_bThickPen = FALSE;
m_nThinWidth = 2; // default thin pen is 2 pixels wide
m_nThickWidth = 5; // default thick pen is 5 pixels wide
ReplacePen(); // initialize pen according to current width
}
//////////////////
// ***PD: This function REALLY initializes a new document, as opposed to
// OnNewDocument. That is, it performs the initialization required
// to use the document. It's called when the user invokes the File New
// command from the menu. This implementation doesn't actually do anything,
// it just sleeps to simulate some long operation a real app might do.
//
BOOL CScribbleDoc::Initialize()
{
// This implementation doesn't actually do anything
// except sleep for three seconds to simulate a lengthy operation
//
CWaitCursor wait; // display wait cursor
Sleep(3000);
return m_bInitialized = TRUE;
}
scribvw.h
////////////////////////////////////////////////////////////////
// Modified SCRIBBLE Copyright 1996 Microsoft Systems Journal.
// Portions Copyright (C) 1992-1995 Microsoft Corporation.
// NOTE: Only changes from original SCRIBBLE code are shown.
// Full source available on any MSJ bulletin board.
class CScribbleView : public CView {
protected:
// ***PD new override
BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
// ***PD overrides
virtual void OnDraw(CDC* pDC);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
scribvw.cpp
////////////////////////////////////////////////////////////////
// Modified SCRIBBLE Copyright 1996 Microsoft Systems Journal.
// Portions Copyright (C) 1992-1995 Microsoft Corporation.
// NOTE: Only changes from original SCRIBBLE code are shown.
// Full source available on any MSJ bulletin board.
#include "stdafx.h"
#include "Scribble.h"
#include "ScribDoc.h"
#include "ScribVw.h"
.
.
.
void CScribbleView::OnDraw(CDC* pDC)
{
CScribbleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (pDoc->IsInitialized()) {
// The view delegates the drawing of individual strokes to
// CStroke::DrawStroke().
CTypedPtrList<CObList,CStroke*>& strokeList = pDoc->m_strokeList;
POSITION pos = strokeList.GetHeadPosition();
while (pos != NULL) {
CStroke* pStroke = strokeList.GetNext(pos);
pStroke->DrawStroke(pDC);
}
} else {
// ***PD Draw "empty" background if doc not initialized.
// Note: be sure to use COLOR_3DSHADOW to get the
// right logical color, in case user has customized it.
//
CRect rc;
GetClientRect(&rc);
HGDIOBJ hOldBrush = pDC->SelectObject(GetSysColorBrush(COLOR_3DSHADOW));
pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);
pDC->SelectObject(hOldBrush);
}
}
//////////////////
// ***PD: Change so drawing is allowed only if doc is initialized.
//
void CScribbleView::OnLButtonDown(UINT, CPoint point)
{
CScribbleDoc* pDoc = GetDocument();
if (pDoc->IsInitialized()) {
m_pStrokeCur = pDoc->NewStroke();
// Add first point to the new stroke
m_pStrokeCur->m_pointArray.Add(point);
SetCapture(); // Capture the mouse until button up.
m_ptPrev = point; // Serves as the MoveTo() anchor point for the
// LineTo() the next point, as the user drags the
// mouse.
}
return;
}
//////////////////
// ***PD: If doc not initialized, disable all doc/view commands by
// returning FALSE here--i.e., do not even route through doc/view msg maps.
// Command routing behaves as if there were no doc nor view. NOTE: this
// only works if CFrameWnd::m_bAutoMenuEnable = TRUE, the default.
//
BOOL CScribbleView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CScribbleDoc *pDoc = GetDocument();
return pDoc->IsInitialized() ?
CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo) : FALSE;
}