Figure 1   Const

CONST.CPP

 ////////////////////////////////////////////////////////////////
// Copyright 1996 Microsoft Systems Journal. 
//
// This program illustrates how to cast away const-ness
// When you compile, you will get three errors (See below).
//
// Microsoft:     cl  /c const.cpp
// Borland:       bcc /c const.cpp

//////////////////
// A class where functions that are really const are not declared such.
//
class Size {
private:
   int cx;
   int cy;
public:
   Size(int w, int h)   { cx=w; cy=h; }
   int Width()          { return cx; }       // should be const
   int Height()         { return cy; }       // should be const
};

//////////////////
// A class that tries to use const where appropriate
//
class Window {
private:
   int   m_bSizeKnown;     // whether size is known or not
   Size  m_size;           // known size
   void  FigureOutSize()   { /* pretend this actually does something */ }
public:
   Window();
   int Width() const;      // getting the width doesn't change the object
   int Height() const;     // ..ditto for height
};

Window::Window() : m_size(0,0)
{
   m_bSizeKnown = 0;
}

//////////////////
// This function generates two compiler errors.
//
int Window::Width() const
{
   if (!m_bSizeKnown) {
      FigureOutSize();       // Error #1: FigureOutSize is non-const
      m_bSizeKnown = 1;      // Error #2: I'm modifying a member!
      
      // I don't want either of these to "count" as a change, since I'm 
      // not really modifying the Window. m_bSizeKnown is just an 
      // implementation hack so I only have to compute the size once.
      //
   }

   // Error #3: The author of the Size class forgot to declare Size::Width
   // const. It really is const, but the compiler doesn't know that, so it
   // complains:
   return m_size.Width();
}

//////////////////
// This similar function shows how to work around the errors.
// Window::Height compiles with no errors.
//
int Window::Height() const
{
   if (!m_bSizeKnown) {

      // Error #1,#2 1 workaround: The way the compiler handles const 
      // functions is by effectively declaring "this" a const pointer. 
      // In other words, "this" is really "const Window*", not "Window*". 
      // So all you have to do is cast away the const-ness.
      //
      ((Window*)this)->FigureOutSize();
      ((Window*)this)->m_bSizeKnown = 1;
   }

   // Error# 3 workaround: Likewise, in a const member function, the
   // compiler considers all class members const, so it's as if m_size
   // were "const Size m_size" instead of "Size m_size". So to defeat the
   // compiler, you can again cast the const-ness away:

   return ((Size&)m_size).Height();   // cast to (non-const) reference
}

Figure 2   Scribble

Figure 2 Scribble//////////////////

SCRIBBLE.H

 #include "resource.h"       // main symbols

class CScribbleApp : public CWinApp {
public:
.
.
.
   //{{AFX_MSG(CScribbleApp)
.
.
.
   afx_msg void OnFileSample();  // new command handler
   //}}AFX_MSG
.
.
.
};

SCRIBBLE.RC

 .
.
.
/////////////////////////////////////////////////////////////////////////////
//
// SCRIBDOC
//
IDR_MAINFRAME SCRIBDOC MOVEABLE PURE  "res\\sample.scb"
.
.
.

SCRIBBLE.CPP

 ////////////////////////////////////////////////////////////////
// Modified SCRIBBLE Copyright 1996 Microsoft Systems Journal. 
//
// This modified SCRIBBLE program shows how to store a document in the
// resource file and then load it using the normal serialization mechanism.
// For brevity, only the changes to the original Scribble files are shown.
// 
#include "stdafx.h"

.
.
.

BEGIN_MESSAGE_MAP(CScribbleApp, CWinApp)
.
.
.
   ON_COMMAND(ID_FILE_SAMPLE, OnFileSample)  // New command
END_MESSAGE_MAP()

.
.
.

//////////////////
// Handle "File New Sample"
//
void CScribbleApp::OnFileSample() 
{
   OnFileNew();   // create new (empty) doc
   CScribbleDoc* pDoc = (CScribbleDoc*)
      ((CFrameWnd*)m_pMainWnd)->GetActiveFrame()->GetActiveDocument();
   ASSERT_VALID(pDoc);
   ASSERT_KINDOF(CScribbleDoc, pDoc);

   // Use new fn to load resource doc IDR_MAINFRAME
   VERIFY(pDoc->OnOpenDocument(IDR_MAINFRAME));

   // give it a name
   pDoc->SetPathName(_T("Sample.SCB"));
}

SCRIBDOC.H

 .
.
.
class CScribbleDoc : public CDocument {
protected:
.
.
.
   virtual BOOL OnOpenDocument(UINT uIDRes); // new overloaded function
.
.
.
};
.
.
.

SCRIBDOC.CPP

 #include "stdafx.h"
.
.
.

//////////////////
// Overloaded version of OnOpenDocument loads SCRIBBLE doc from 
// resource data instead of disk file. Arg is ID of resource.
//
BOOL CScribbleDoc::OnOpenDocument(UINT uID)
{
   // Load the resource into memory
   //
   HINSTANCE hinst = AfxGetInstanceHandle();
   HRSRC hRes = FindResource(hinst, (LPCSTR)uID, "SCRIBDOC");
   if (hRes==NULL) {
      TRACE("Couldn't find SCRIBDOC resource %d!\n", uID);
      return FALSE;
   }
   DWORD len = SizeofResource(hinst, hRes);

   // Note: Under Win16, you have to do Lock/UnlockResource, but
   // in Win32 these are no-ops and you can just cast the HGLOBAL
   // returned by LoadResource to a BYTE*.
   //
   BYTE* lpRes = (BYTE*)LoadResource(hinst, hRes);
   ASSERT(lpRes);

   // Create mem file
   // 
   CMemFile file(lpRes, len);

   // Create archive and load from it. 
   // This is just like CDocument::OnOpenDocument
   //
   BOOL bRet = FALSE;      // assume failure
   DeleteContents();

   CArchive ar(&file, CArchive::load);
   ar.m_pDocument = this;
   ar.m_bForceFlat = FALSE;
   TRY {
      CWaitCursor wait;    // hourglass
      Serialize(ar);       // do normal Serialize thing
      ar.Close();          // done
      bRet = TRUE;         // success
      SetModifiedFlag(FALSE);

   } CATCH_ALL(e) {
      TRACE("Unexpected exception loading SCRIBDOC %d\n", uID);
      DeleteContents();
         
   } END_CATCH_ALL

   FreeResource((HANDLE)lpRes);
   return bRet;
}
                                             .
                                             .
                                             .

Figure 4   How to use CMemFile

 BOOL CScribbleDoc::OnOpenDocument(UINT uID)
{
   BYTE* lpRes = // load resource uID
.
.
.
   // Create memfile. lpRes points to resource 
   // in memory; len is size in bytes. 
   //
   CMemFile file(lpRes, len);

   // Create archive and Serialize. This is just 
   // like CDocument::OnOpenDocument(LPCSTR).
   //
   BOOL bRet = FALSE;      // assume failure
   DeleteContents();

   CArchive ar(&file, CArchive::load);
   ar.m_pDocument = this;
   ar.m_bForceFlat = FALSE;
   Serialize(ar); // do it
}

Figure 5   Changes for SCBM

 ////////////////////////////////////////////////////////////////
// Modifications to CScribbleDoc for solution #1
// (In SCRIBBLE\ScribDoc.cpp)

//////////////////
// **MOD**
// Override SetModified flag to notify view when doc has changed,
// so the view can tell the frame to update the title.
//
void CScribbleDoc::SetModifiedFlag(BOOL bModified)
{
   if (IsModified() != bModified) {
      CDocument::SetModifiedFlag(bModified);
      UpdateFrameCounts();
      CString title = GetTitle();
      int asterisk = title.GetLength()-1;
      if (asterisk >=0 && title.GetAt(asterisk)=='*') {
         if (!bModified)
            title.SetAt(asterisk,0);
      } else if (bModified)
         title += '*';
      SetTitle(title);
   }
}
OD1

Figure 6   Changes for SCBMOD2

 ////////////////////////////////////////////////////////////////
// Modifications to CChildFrame for solution #2
// (In SCRIBBLE\ChildFrm.cpp)

#include <afxpriv.h>    // for WM_IDLEUPDATECMDUI
.
.
.

BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
   //{{AFX_MSG_MAP(CChildFrame)
   ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI) // handle idle UI msg
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()

CChildFrame::CChildFrame()
{
   m_bModLast = -1;        // initialize modified-state memory
}
//////////////////
// Override to add asterisk if doc is modified.
//
void CChildFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
   CMDIChildWnd::OnUpdateFrameTitle(bAddToTitle);
   CDocument* pDoc = GetActiveDocument();
   if (pDoc && pDoc->IsModified()) {
      // if doc modified, append * to normal title
      CString title;
      GetWindowText(title);
      title += '*';
      SetWindowText(title);
   }
}

//////////////////
// **MOD**
// Handle WM_IDLEUPDATECMDUI to update modified indicator if necessary.
//
LRESULT CChildFrame::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM)
{
   // Only update the title if the modified state has changed.
   // Otherwise, the title bar will flicker.
   // 
   CDocument* pDoc = GetActiveDocument();
   if (m_bModLast != pDoc->IsModified()) {
      // mod state has changed: set flag telling MFC to update title
      m_nIdleFlags |= idleTitle; 
      m_bModLast = pDoc->IsModified();
   }

   // do the default thing
   CMDIChildWnd::OnIdleUpdateCmdUI();

   return 0L;
}