Creating an MDI Application (C++ 4.0 and later)

Take the following steps to start an MDI (Multiple Document Interface) project and to add some code that positions, scales, and displays an image in a dialog box.

1. Start the Microsoft Developer Studio for Visual C++, version 4.0.

2. Select the File >New menu option, select Project Workspace, and click the OK button.

3. In the New Project Workspace dialog box, do the following:

a. In the Type list box, select MFC AppWizard (exe).

b. In the Name text box, specify mditutor.

c. In the Location text box, specify the path of the project.

d. In the Platforms list box, check Win32 Platforms.

e. Click the Create button.

4. In the Step 1 dialog box, do the following:

a. Select Multiple Documents.

b. Click the Next button.

5. In the Step 2 of 6 dialog box, do the following:

a. Select None for Database support.

b. Click the Next button.

6. In the Step 3 of 6 dialog box, do the following:

a. Select None for OLE compound document support.

b. Select OLE controls for the type of OLE support.

c. Click the Next button.

7. In the Step 4 of 6 dialog box, do the following:

a. Ensure that that 3D Controls and Printing and Print Preview are selected as features to include.

b. Click the Next button.

8. In the Step 5 of 6 dialog box, do the following:

a. For comments, ensure that Yes, Please is selected.

b. For how to use the MFC library, select As a statically linked library.

c. Click the Next button.

9. In the Step 6 of 6 dialog box, do the following:

a. Select CMditutorView from the class list that AppWizard will create so that it appears in the Class name entry field.

b. Change the Base class from CView to CFormView.

c. Click the Finish button.

10. Read New Project Information, and click OK. (The AppWizard creates the project files and opens the project.)

11. Change the resource file to add a LEAD control to the mditutor dialog template form as follows:

a. In the Project Workspace, click the ResourceView tab.

b. Double-click the mditutor resources folder to open it.

c. Double-click the Dialog folder to open it.

d. Double-click IDD_MDITUTOR_FORM to design the form.

e. Select the TODO... text control; then press the Delete key to delete it.

f. From the main menu, select Insert > Component. (The Component Gallery appears.)

g. Click the OLE Controls tab.

h. Double-click the LEAD Control icon. (The Confirm Classes dialog box appears.)

i. Ensure that both CLead and CPicture are checked.

j. Click OK to complete the selection; then click Close to close the Component Gallery. (The LEAD control appears in the Controls toolbar.)

k. image\btnlead.gif Click the LEAD control icon; then click the mditutor dialog box to add the control to the dialog box.

l. Double-click the new LEAD control to edit its properties.

m. Change the ID to IDC_LEAD1.

n. Press Ctrl-F4 to close all windows back to the Project Workspace.

12. Do the following to add m_Lead1 to the CMditutorView class and link the variable to the LEAD control using dynamic data exchange:

a. From the main menu, select View > ClassWizard. (The MFC ClassWizard dialog box appears.)

b. Click the Member Variables tab.

c. In the Class Name box, select CMditutorView.

d. In the Control IDs list, select IDC_LEAD1.

e. Click the Add Variable... button.

f. Specify m_Lead1 as the variable name, and Control as the category.

g. Click OK to close the dialog box.

13. Do the following to add code to the OnInitialUpdate function:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CMditutorView.

c. In the Object IDs list box, select CMditutorView.

d. In the Messages list box, select OnInitialUpdate.

e. Click the Add function button.

f. Click the Edit Code button to start entering the code.

14. Edit the OnInitialUpdate() function to add the following code after the line that says //TODO: Add your specialized code here:

CDocument *pDoc = GetDocument();

int nRet = m_Lead1.Load((LPCTSTR)pDoc->GetPathName(), 0, 1, 1);

if (nRet )
{
   char szBuffer[30];
   wsprintf(szBuffer, "Load Error: Error code %d", nRet);
   AfxMessageBox(szBuffer);

   m_Lead1.SetBitmap(0);
   // Parent of view is MDI Child frame window
   CFrameWnd *pMDIFrame = GetParentFrame(); 
   pMDIFrame->PostMessage(WM_CLOSE);
}
else
{
   m_Lead1.SetPaintPalette(PAINTPALETTE_AUTO);

   CRect rcRect; 
   GetClientRect(rcRect);
   m_Lead1.MoveWindow(rcRect);
}

15. Add the L_OCX.H and L_OcxErr.H files, which define LEAD constants, to your project as follows:

a. Copy the \lead\include\L_OCX.H and l_ocxerr.h files to your project directory.

b. In the Project Workspace, click the FileView tab.

b. Double-click the Dependencies folder to open it.

c. Double-click the StdAfx.h file to edit it.

d. Add the following line to the end of the file:

#include "L_OCX.H"

16. In the file Mditutor.CPP, find the function CMditutorApp::InitInstance() and comment out some lines as follows:

// Parse command line for standard shell commands, DDE, file open
// CCommandLineInfo cmdInfo;
// ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line
// if (!ProcessShellCommand(cmdInfo))
// return FALSE;

17. Press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CMditutorView.

c. In the Object IDs list box, select CMditutorView.

d. In the Messages list box, select WM_SIZE.

e. Click the Add function button.

f. Click the Edit Code button to start entering the code.

18. Edit the OnSize() function to add the following code after the line that says //TODO: Add your message handler code here:

if (IsWindow(m_Lead1.m_hWnd))
  m_Lead1.MoveWindow(0, 0, cx, cy);

19. Press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CMainFrame.

c. In the Object IDs list box, select CMainFrame.

d. In the Messages list box, select WM_PALETTECHANGED.

e. Click the Add function button.

f. Click the Edit Code button to start entering the code.

20. Edit the OnPaletteChanged() function to add the following code after the line that says //TODO: Add your message handler code here:

CMDIChildWnd* pMDIChildWnd = MDIGetActive();
if (pMDIChildWnd == NULL)
  return; // no active MDI child frame

SendMessageToDescendants(WM_DOREALIZE,
  (WPARAM)pFocusWnd->m_hWnd, (LPARAM) TRUE);

21. Press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CMainFrame.

c. In the Object IDs list box, select CMainFrame.

d. In the Messages list box, select WM_QUERYNEWPALETTE.

e. Click the Add function button.

f. Click the Edit Code button to start entering the code.

22. Edit the OnQueryNewPalette() function so that it appears as follows:

BOOL CMainFrame::OnQueryNewPalette() 
{
  // always realize the palette for the active view
  CMDIChildWnd* pMDIChildWnd = MDIGetActive();
  if (pMDIChildWnd == NULL)
    return FALSE; // no active MDI child frame (no new palette)
  CView* pView = pMDIChildWnd->GetActiveView();
  ASSERT(pView != NULL);

  // just notify the target view
  return((BOOL) pView->SendMessage(WM_DOREALIZE, 
                         (WPARAM)m_hWnd, (LPARAM) FALSE));
}

23. Edit the MDITUTOR.H file and add the following line after the preprocessing:

#define WM_DOREALIZE  (WM_USER + 512)

24. Edit the MDITUTORVIEW.H file and insert the following line just before DECLARE_MESSAGE_MAP():

afx_msg LRESULT OnDoRealize(WPARAM wParam, LPARAM lParam);

25. Edit the MditutorView.CPP file and add the following function:

LRESULT CMditutorView::OnDoRealize(WPARAM wParam, LPARAM lParam)
{
    if (!m_Lead1.m_hWnd  ||  !m_Lead1.GetBitmap())
         return FALSE;

    if(lParam)
    {
        return m_Lead1.SendMessage(WM_PALETTECHANGED, wParam);
    }
    else
    {
        UINT nColorsChanged = 0;
        CDC* pdc;
        pdc = theApp.m_pMainWnd->GetDC();
        HPALETTE hpal = 
           (HPALETTE)m_Lead1.GetPalette((OLE_HANDLE) pdc->m_hDC);
      if(hpal)
      {
           CPalette pal;
           pal.Attach(hpal);
          CPalette* oldPalette = pdc->SelectPalette(&pal, (BOOL) lParam);
          nColorsChanged = pdc->RealizePalette();
          if (nColorsChanged > 0)
                m_Lead1.InvalidateRect(NULL, FALSE);
          pdc->SelectPalette(oldPalette, TRUE);
      }
        theApp.m_pMainWnd->ReleaseDC(pdc);
      return ((LRESULT) (BOOL) (nColorsChanged > 0));
    }
}

26. In the MditutorView.CPP file, look for the following lines:

BEGIN_MESSAGE_MAP(CMditutorView, CFormView)
  //{{AFX_MSG_MAP(CMditutorView)

After these lines, add the following line:

ON_MESSAGE(WM_DOREALIZE, OnDoRealize)

Also, near the top of the file, add the following line:

extern CMditutorApp  theApp;

27. Press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CMditutorView.

c. In the Object IDs list box, select CMditutorView.

d. In the Messages list box, select OnActivateView.

e. Click the Add function button.

f. Click the Edit Code button to start entering the code.

28. Edit the OnActivateView() function so that it appears as follows:

void CMditutorView::OnActivateView(BOOL bActivate, CView* pActivateView,
                                 CView* pDeactiveView) 
{
  // TODO: Add your specialized code here and/or call the base class

  CFormView::OnActivateView(bActivate, pActivateView, pDeactiveView);
  if (bActivate)
  {
      ASSERT(pActivateView == this);
      OnDoRealize((WPARAM)theApp.m_pMainWnd->m_hWnd, 
                (LPARAM) FALSE);   // same as SendMessage(WM_DOREALIZE);
  }
}

29. To remove the default printing functions, press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CMditutorView.

c. In the Object IDs list box, select CMditutorView.

d. In the Messages list box, select OnPrint.

e. Click Delete function and answer YES to the dialog box.

f. In the Messages list box, select OnBeginPrinting.

g. Click Delete function and answer YES to the dialog box.

h. Click OK to exit ClassWizard.

i. Go to MditutorView.CPP and manually delete the functions CMditutorView::OnPrint() and CMditutorView::OnBeginPrinting().

30. To add new printing functions, press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CMditutorView.

c. In the Object IDs list box, select CMditutorView.

d. In the Messages list box, select OnDraw.

e. Click the Add function button.

f. Click the Edit Code button to start entering the code.

31. Edit the OnDraw() function so that it appears as follows:

void CMditutorView::OnDraw(CDC* pDC)
{
  CRect rcClip;
  CSize winext;
  CSize viewext;
  CSize paintext;

  CMditutorDoc* pDoc = GetDocument();
  ASSERT_VALID(pDoc);

  if(pDC->IsPrinting())
  {
    pDC->SaveDC();
    ::GetWindowExtEx(pDC->m_hDC, &winext);
    ::GetViewportExtEx(pDC->m_hDC, &viewext);
    paintext.cx = MulDiv((int) m_Lead1.GetBitmapWidth(), viewext.cx, winext.cx);
    paintext.cy = MulDiv((int) m_Lead1.GetBitmapHeight(), viewext.cy, winext.cy);
    ::SetMapMode(pDC->m_hDC, MM_TEXT); 
    m_Lead1.Render((OLE_HANDLE) pDC->m_hDC, (float) 0, (float) 0, (float)
                   paintext.cx, (float) paintext.cy);
    pDC->RestoreDC(-1);
  }
}

32. To remove unused menu items, click the ResourceView tab of the Project Workspace, and do the following:

a. Open the mditutor resources folder.

b. Open the Menu folder.

c. Double-click on IDR_MAINFRAME

d. Click the File menu; then select the New menu item and press the Delete key.

e. Double-click on IDR_MDITUTORTYPE.

f. Click the File menu option; then select and delete the following items: New, Save, and Save As....

g. Press Ctrl-F4 twice to return to the Project Workspace.

33. On the main menu, select Build > Build mditutor.exe to build the project.

34. On the main menu, select Build > Execute mditutor.exe to run the project.