Patrick Craig > IRIS Explorer > CWinApp Modules

Converting a CWinApp application into an IRIS Explorer 5.0 MFC module

[Return to main IRIS Explorer page]

Introduction

With the introduction of Group Compilation at version 5.0 of IRIS Explorer, the way that CWinApp modules were built was changed in order to allow multiple instances of a CWinApp module in a single executable. There can only be one CWinApp object in an executable, so the single CWinApp object is now internal to the mfcMcw50.obj object file and the CWinApp object in the module code is replaced by a cxModuleApp object.

NB : Using the Group Compilation feature of IRIS Explorer 5.0, you can create a new module containing multiple instances of a single CWinApp module. However, you cannot create a new module containing more than one type of CWinApp module. This is because CWinApp modules use resource files and if you attempt to compile an executable containing more than one resource file, the first file is used and the others are ignored. This is not a problem with the distributed modules as there is only one CWinApp module (Render).

The downloadable example code was created using the Japanese version of Visual C++. In the source listings below, the Japanese automatically generated comments have been removed. Code in red is code that needs to be removed. Code in brown is code that needs to be modified. Code in green is code that needs to be added.

NB : All CWinApp modules will almost certainly crash on startup if you build them with the Debug flag set!

Example using an empty Single Document Interface application

The original code for this application was generated using the MFC AppWizard(exe) on Visual C++ 6.0. The name of the application was MFCMod. At Step one, the Single Document Interface option was chosen, all the other options were the default settings. Before attempting to convert an existing application it is strongly recommended that all files are backed up. The coverted source for the example module can be downloaded here. As well as the changes outlined below, the "Print Preview" menu item was removed from the file menu. The reason for this is explained in the next section.
  1. Replace CWinApp with cxModuleApp


  2. In the main application header file (MFCMod.h) replace CWinApp with cxModuleApp and include the header <cx/winMcw.h>. As the application class is no longer a CWinApp you cannot use the CWinApp members and functions. Normally the application overrides the CWinApp InitInstance function and uses the MESSAGE_MAP macros to handle command messages from menu items. With the cxModuleApp class, you create a new initialization function to replace InitInstance that will be called from the module's init hook function. This function can be called anything, in this example it is called init. The MESSAGE_MAP macro code is removed and the messages previously handled by the application are instead handled by either the Frame, View or Document class (the "Save" and "Save As" message handlers have to be handled by either the View or Document Class).

    Original MFCMod.h
    #if !defined(AFX_MFCMOD_H__F6754EB4_EB4C_11D4_969C_0000F8785F0A__INCLUDED_)
    #define AFX_MFCMOD_H__F6754EB4_EB4C_11D4_969C_0000F8785F0A__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    #ifndef __AFXWIN_H__
    	#error include 'stdafx.h' before including this file for PCH
    #endif
    
    #include "resource.h"  
    
    class CMFCModApp : public CWinApp
    {
    public:
    	CMFCModApp();
    
    	public:
    	virtual BOOL InitInstance();
    
    	afx_msg void OnAppAbout();
    	DECLARE_MESSAGE_MAP()
    };
    
    #endif // !defined(AFX_MFCMOD_H__F6754EB4_EB4C_11D4_969C_0000F8785F0A__INCLUDED_)
    
    Converted MFCMod.h
    #if !defined(AFX_MFCMOD_H__F6754EB4_EB4C_11D4_969C_0000F8785F0A__INCLUDED_)
    #define AFX_MFCMOD_H__F6754EB4_EB4C_11D4_969C_0000F8785F0A__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    #ifndef __AFXWIN_H__
    	#error include 'stdafx.h' before including this file for PCH
    #endif
    
    #include "resource.h"  
    
    #include <cx/winMcw.h>
    
    class CMFCModApp : public cxModuleApp
    {
    public:
    	CMFCModApp();
    
    	void init();
    };
    
    #endif // !defined(AFX_MFCMOD_H__F6754EB4_EB4C_11D4_969C_0000F8785F0A__INCLUDED_)
    

    In the original application InitInstance function, several CWinApp functions are called to load registry settings and parse the command line. This functionality is not required in an IRIS Explorer module, so these functions can be removed. To create a new empty document when the module starts up we call the CSingleDocTemplate function OpenDocumentFile with a NULL document path. The about dialog code can be moved to one of the other classes if required.

    Original MFCMod.cpp
    #include "stdafx.h"
    #include "MFCMod.h"
    
    #include "MainFrm.h"
    #include "MFCModDoc.h"
    #include "MFCModView.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    BEGIN_MESSAGE_MAP(CMFCModApp, CWinApp)
    	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
    	ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
    	ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
    	ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
    END_MESSAGE_MAP()
    
    CMFCModApp::CMFCModApp()
    {
    }
    
    CMFCModApp theApp;
    
    BOOL CMFCModApp::InitInstance()
    {
    	AfxEnableControlContainer();
    
    #ifdef _AFXDLL
    	Enable3dControls();	
    #else
    	Enable3dControlsStatic();
    #endif
    
    	SetRegistryKey(_T("Local AppWizard-Generated Applications"));
    
    	LoadStdProfileSettings(); 
    
    	CSingleDocTemplate* pDocTemplate;
    	pDocTemplate = new CSingleDocTemplate(
    		IDR_MAINFRAME,
    		RUNTIME_CLASS(CMFCModDoc),
    		RUNTIME_CLASS(CMainFrame),      
    		RUNTIME_CLASS(CMFCModView));
    	AddDocTemplate(pDocTemplate);
    
    	CCommandLineInfo cmdInfo;
    	ParseCommandLine(cmdInfo);
    
    	if (!ProcessShellCommand(cmdInfo))
    		return FALSE;
    
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    class CAboutDlg : public CDialog
    {
    public:
    	CAboutDlg();
    
    	enum { IDD = IDD_ABOUTBOX };
    
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX); 
    
    protected:
    	DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    END_MESSAGE_MAP()
    
    void CMFCModApp::OnAppAbout()
    {
    	CAboutDlg aboutDlg;
    	aboutDlg.DoModal();
    }
    
    
    Converted MFCMod.cpp
    #include "stdafx.h"
    #include "MFCMod.h"
    
    #include "MainFrm.h"
    #include "MFCModDoc.h"
    #include "MFCModView.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    CMFCModApp::CMFCModApp()
    {
    }
    
    void CMFCModApp::init()
    {
    	AfxEnableControlContainer();
    
    	CSingleDocTemplate* pDocTemplate;
    	pDocTemplate = new CSingleDocTemplate(
    		IDR_MAINFRAME,
    		RUNTIME_CLASS(CMFCModDoc),
    		RUNTIME_CLASS(CMainFrame),    
    		RUNTIME_CLASS(CMFCModView));
    	pDocTemplate->OpenDocumentFile(NULL);
    }
    
  3. Modify Frame Class


  4. Normally CWinApp modules will have a drawing area widget in which the frame window is displayed. In order to do this you have to call the mcwMFCReparentWindow function from within the Frame class OnCreate function. The Frame class code will pick up the header for this function from MFCMod.h. In this example, the drawing area widget port is called "window".

    Converted CMainFrame OnCreate
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    
    	if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
    		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
    		!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
    	{
    		TRACE0("Failed to create toolbar\n");
    		return -1;
    	}
    
    	if (!m_wndStatusBar.Create(this) ||
    		!m_wndStatusBar.SetIndicators(indicators,
    		  sizeof(indicators)/sizeof(UINT)))
    	{
    		TRACE0("Failed to create status bar\n");
    		return -1; 
    	}
    
    	m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
    	EnableDocking(CBRS_ALIGN_ANY);
    	DockControlBar(&m_wndToolBar);
    
    	mcwMFCReparentWindow(this, "window");
    
    	return 0;
    }
    
  5. Add message handlers from application class to Document class


  6. These handlers could be moved to the View class or, with the exception of the "Save" and "Save As" handlers, to the Frame class. The MESSAGE_MAP macros can be modified by hand or by using the ClassWizard. Dummy open and save dialogs have been added to the OnFileOpen and OnFileSaveAs functions to demonstrate that the message handlers work.

    Converted MFCModDoc.h
    #if !defined(AFX_MFCMODDOC_H__F6754EBA_EB4C_11D4_969C_0000F8785F0A__INCLUDED_)
    #define AFX_MFCMODDOC_H__F6754EBA_EB4C_11D4_969C_0000F8785F0A__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    
    class CMFCModDoc : public CDocument
    {
    protected:
    	CMFCModDoc();
    	DECLARE_DYNCREATE(CMFCModDoc)
    
    public:
    
    public:
    
    	public:
    	virtual BOOL OnNewDocument();
    	virtual void Serialize(CArchive& ar);
    
    public:
    	virtual ~CMFCModDoc();
    #ifdef _DEBUG
    	virtual void AssertValid() const;
    	virtual void Dump(CDumpContext& dc) const;
    #endif
    
    protected:
    
    protected:
    	afx_msg void OnFileSave();
    	afx_msg void OnFileSaveAs();
    	afx_msg void OnFileNew();
    	afx_msg void OnFileOpen();
    	afx_msg void OnAppAbout();
    	DECLARE_MESSAGE_MAP()
    };
    
    #endif // !defined(AFX_MFCMODDOC_H__F6754EBA_EB4C_11D4_969C_0000F8785F0A__INCLUDED_)
    
    Converted MFCModDoc.cpp
    #include "stdafx.h"
    #include "MFCMod.h"
    
    #include "MFCModDoc.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    IMPLEMENT_DYNCREATE(CMFCModDoc, CDocument)
    
    BEGIN_MESSAGE_MAP(CMFCModDoc, CDocument)
    	ON_COMMAND(ID_FILE_SAVE, OnFileSave)
    	ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
    	ON_COMMAND(ID_FILE_NEW, OnFileNew)
    	ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
    	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
    END_MESSAGE_MAP()
    
    
    CMFCModDoc::CMFCModDoc()
    {
    }
    
    CMFCModDoc::~CMFCModDoc()
    {
    }
    
    BOOL CMFCModDoc::OnNewDocument()
    {
    	if (!CDocument::OnNewDocument())
    		return FALSE;
    
    	return TRUE;
    }
    
    void CMFCModDoc::Serialize(CArchive& ar)
    {
    	if (ar.IsStoring())
    	{
    	}
    	else
    	{
    	}
    }
    
    #ifdef _DEBUG
    void CMFCModDoc::AssertValid() const
    {
    	CDocument::AssertValid();
    }
    
    void CMFCModDoc::Dump(CDumpContext& dc) const
    {
    	CDocument::Dump(dc);
    }
    #endif //_DEBUG
    
    void CMFCModDoc::OnFileSave() 
    {
    }
    
    void CMFCModDoc::OnFileSaveAs() 
    {
    	CFileDialog openFile(FALSE);
    	openFile.DoModal();	
    }
    
    void CMFCModDoc::OnFileNew() 
    {
    }
    
    void CMFCModDoc::OnFileOpen() 
    {
    	CFileDialog openFile(TRUE);
    	openFile.DoModal();	
    }
    
    class CAboutDlg : public CDialog
    {
    public:
    	CAboutDlg();
    
    	enum { IDD = IDD_ABOUTBOX };
    
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX); 
    
    protected:
    	DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    END_MESSAGE_MAP()
    
    void CMFCModDoc::OnAppAbout() 
    {
    	CAboutDlg aboutDlg;
    	aboutDlg.DoModal();	
    }
    
  7. Create module resources and interface code


  8. Using the module builder, create the module resources for the module in a new directory. From "Module | Options..." set the type to MFC and from "Module | Hook functions..." add an initialization function. Specify a user function name and select "C++" as "Language" from the "Function Args..." popup. In this example the user function is called "doit" and the initializastion function is called "init". The example module has a single parameter input port called "window" with a drawing area widget.

    Create a funtion prototype for the module from "Prototypes | Create Function Prototype", in this case "modIF.cpp". Add stdafx.h and MFCMod.h to the included header files and add a single global application class object. From the initialization function, call the application initialization function you added at stage one.

    Module interface code modIF.cpp
    /* Declarations from the module resource file */
    #include "MFCMod.uf.h"
    #include "stdafx.h"
    #include "MFCMod.h"
    
    CMFCModApp modIF;
    
    
    void doit ( void  )
    {
    
    }
    
    #include <cx/UserFuncs.h>
    
    #ifdef __cplusplus
    	extern "C" {
    #endif
    /* Hook function for Explorer module actions. */
    void init(void)
    {
    	modIF.init();
    }
    
    #ifdef __cplusplus
    }
    #endif
    

  9. Put it all together


  10. Copy all the source files and the res directory from the Visual C++ project to the module directory. Add the .cpp (you don't need stdafx.cpp) and .rc files to the module builder "User Func File" text box and build the module.


More advanced operations

  1. m_pMainWnd


  2. In the above example, the "Print Preview" menu item was removed from the File menu. This is because the default handler for this menu item attempts to access AfxGetApp()->m_pMainWnd. AfxGetApp() returns the single CWinApp instance in the executable, i.e. that in the mcw library. The m_pMainWnd member for this instance is undefined (NULL), so the application crashes when the "Print Preview" menu item is selected.

    m_pMainWnd is undefined in the mcw CWinApp instance so that modules can set this member to their own frame window. To do this you override the CFrameWnd PreTranslateMessage function and set m_pMainWnd to the module's frame window. Setting m_pMainWnd in this way means that the module will still work correctly if a group containing more than one instance of the module is compiled into a single module.

    Modified CMainFrame PreTranslateMessage
    BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) 
    {
    	AfxGetApp()->m_pMainWnd = this;
    	return CFrameWnd::PreTranslateMessage(pMsg);
    }
    
  3. Application OnIdle and PreTranslateMessage


  4. The CWinApp class has virtual OnIdle and PreTranslateMessage functions that may be of use to module writers. These functions are exposed via equivalent virtual OnIdle and PreTranslateMessage functions in the cxModuleApp class. The cxModuleApp functions are only called for applications that have been registered with the mcw CWinApp by calling the cxModuleAppRegister function. Do not call the CWinApp functions from the overridden cxModuleApp functions.

    Registering an application in the constuctor
    CMFCModApp::CMFCModApp()
    {
    	cxModuleAppRegister(this);
    }
    
  5. Multiple Document Interface applictions


  6. The process for converting a Multiple Document Interface (MDI) is slightly more complicated than for a Single Document Interface (SDI) Application. In the source listings below, code in green indicates additional code required by MDI modules and brown indicates optional code. Otherwise the process is the same as for an SDI application. The source for this example can be downloaded here.

    In an MDI application, new windows are created when a document is created or loaded from a file. This functionality is provided by the CMultiDocTemplate object created in the application initialization function. In order to use this object, a pointer to the object is included as a member of the application class. So that other classes can access this object, a reference to the application instance in the module interface code is added to the application header file.

    Converted CMDIMod.h
    #include <cx/winMcw.h>
    
    class CMDIModApp : public cxModuleApp
    {
    public:
    	CMDIModApp();
    	void init();
    	CMultiDocTemplate *m_DocTemplate;
    };
    
    extern CMDIModApp modIF;
    
    Converted CMDIMod.cpp
    #include "stdafx.h"
    #include "MDIMod.h"
    
    #include "MainFrm.h"
    #include "ChildFrm.h"
    #include "MDIModDoc.h"
    #include "MDIModView.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    CMDIModApp::CMDIModApp()
    {
    }
    
    void CMDIModApp::init()
    {
    	AfxEnableControlContainer();
    
    	m_DocTemplate = new CMultiDocTemplate(
    		IDR_MDIMODTYPE,
    		RUNTIME_CLASS(CMDIModDoc),
    		RUNTIME_CLASS(CChildFrame), 
    		RUNTIME_CLASS(CMDIModView));
    	CMainFrame* pMainFrame = new CMainFrame;
    	if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
    		return;
    	AfxGetApp()->m_pMainWnd = pMainFrame;
    	m_DocTemplate->OpenDocumentFile(NULL);
    	pMainFrame->ShowWindow(SW_SHOW);
    	pMainFrame->UpdateWindow();
    }
    
    In the SDI example above, the "File New" and "File Open" message handlers from the application class were moved to the document class. In an MDI application, when there are no open files, there are no instances of the child window, document or view classes, so these handlers have to be moved to the frame window class. The "Save" and "Save As" messages can still be handled by the document class.

    Example frame window message handlers
    void CMainFrame::OnFileNew() 
    {
    	modIF.m_DocTemplate->OpenDocumentFile(NULL);	
    }
    
    void CMainFrame::OnFileOpen() 
    {
    	CFileDialog openFile(TRUE);
    	if (openFile.DoModal() != IDOK) return;
    	modIF.m_DocTemplate->OpenDocumentFile(openFile.m_ofn.lpstrFile);	
    }
    

Converting an Inventor IVF application

This sections assumes you have already carried out the steps outlined above for a generic SDI or MDI application. The source for the example MDI IVF module can be downloaded here.
  1. Converting the application class


  2. IVF applications use the CWinApp OnIdle (speeds up spining) and PreTranslateMessage (?) functions, so the application class overrides the cxModuleApp functions. Pointers to the main frame window and the document template (whether it is an SDI or MDI application) are also required. The IVF m_nLastOpenedFilterIX member variable is retained.

    Converted IVFMod.h
    #ifndef __AFXWIN_H__
    	#error include 'stdafx.h' before including this file for PCH
    #endif
    
    #include "resource.h"       // main symbols
    
    #include <Ivf/IvfApp.h>
    
    #include <cx/winMcw.h>
    
    class CIVFModApp : public cxModuleApp
    {
    public:
    	CIVFModApp();
    	long m_nLastOpenedFilterIX;
    
    	void init();
    	virtual BOOL OnIdle(LONG lCount);
    	virtual BOOL PreTranslateMessage(MSG *pMsg);
    	CMultiDocTemplate *m_DocTemplate;
    	CFrameWnd *m_pMainFrame;
    };
    
    extern CIVFModApp modIF;
    
    In the application initialization function, the IVF_INIT_INSTANCE macro has to be replaced by CIvfApp::IvfInitInstance as the application class is no longer derived from CWinApp. Pointers to the frame window and document template are also saved in the initialization function.
    In the constructor, cxModuleAppRegister is called to enable the OnIdle and PreTranslateMessage functions, and member variables are initialized. The OnIdle and PreTranslateMessage functions are modified by setting AfxGetApp()->m_pMainWnd and CIvfApp::m_pDocTemplate and removing the calls to the CWinApp functions. Also the CIvfApp IvfGetDocument function is no longer available so the m_pMainWnd GetActiveDocument function is used instead.

    Converted IVFMod.cpp
    #include "stdafx.h"
    #include "IVFMod.h"
    
    #include "MainFrm.h"
    #include "ChildFrm.h"
    #include "IVFModDoc.h"
    #include "IVFModView.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    
    CIVFModApp::CIVFModApp()
    {
    	cxModuleAppRegister(this);
    	m_DocTemplate = NULL;
    	m_pMainFrame = NULL;
    	m_nLastOpenedFilterIX = 0;
    }
    
    IVF_AFX_CONVERSION_METHOD(CIVFModView,CIVFModDoc)
    
    void CIVFModApp::init()
    {
    	static int cArgs[]= {
    		TRUE,		// Decoration
    		TRUE,	// URL Display
    		TRUE,					// Viewpoints
    		TRUE};		// URL Fetch
    
    	CIvfApp::IvfInitInstance(NULL,
    		 NULL,
    		 IvfCvtAfxView,
    		 IvfCvtIvfComponent,
    		 NULL,
    		 NULL,
    		 IvfCvtAfxDoc,
    		 IvfCvtIvfDoc,
    		 IvfCvtAfxFrame,
    		 (void *)cArgs,
    		 FALSE);
    
    	m_DocTemplate = new CMultiDocTemplate(
    		IDR_IVFMODTYPE,
    		RUNTIME_CLASS(CIVFModDoc),
    		RUNTIME_CLASS(CChildFrame), // custom MDI child frame
    		RUNTIME_CLASS(CIVFModView));
    	m_pMainFrame = new CMainFrame;
    	if (!m_pMainFrame->LoadFrame(IDR_MAINFRAME))
    		return;
    	AfxGetApp()->m_pMainWnd = m_pMainFrame;
    	m_DocTemplate->OpenDocumentFile(NULL);
    	m_pMainFrame->ShowWindow(SW_SHOW);
    	m_pMainFrame->UpdateWindow();
    }
    
    BOOL CIVFModApp::OnIdle(LONG lCount) 
    {
    	if (modIF.m_pMainFrame == NULL) return FALSE;
    	CIvfApp::m_pDocTemplate = modIF.m_DocTemplate;
    	AfxGetApp()->m_pMainWnd = modIF.m_pMainFrame;
    	CIvfApp::IvfOnIdle(lCount);
    	return FALSE;
    }
    
    BOOL CIVFModApp::PreTranslateMessage(MSG *pMsg) 
    {
    	if (modIF.m_pMainFrame == NULL) return FALSE;
    	AfxGetApp()->m_pMainWnd = modIF.m_pMainFrame;
    	CIvfDocument *pDoc = (CIvfDocument *)modIF.m_pMainFrame->GetActiveDocument();
    	if ((pDoc && pDoc->IvfPreTranslateMessage(pMsg))) return TRUE;
    	return FALSE;
    }
    
  3. Moving the message handlers


  4. The "File New", "File Open" and "About" handlers are moved to the frame class. The "File New" and "File Open" handlers need to be modified slightly for the new application class.

    Converted CMainFrame message handlers
    static char *def_ext[] = {NULL, ".iv", ".wrl"};
    #define NUM_EXT_VALS	3
    
    void CMainFrame::OnFileOpen() 
    {
    	const char szFilter[] =
    	"Inventor Files (*.iv)\0*.iv\0Vrml Files (*.wrl)\0*.wrl\0";
    
    	const char szTitle[] = "Open File";
    
    	CFileDialog openDlg(TRUE);
    
    	openDlg.m_ofn.lpstrTitle = szTitle;
    	openDlg.m_ofn.lpstrFilter = szFilter ;
    	openDlg.m_ofn.nFilterIndex = modIF.m_nLastOpenedFilterIX;
    	openDlg.m_ofn.lpstrCustomFilter = NULL;
    	openDlg.m_ofn.lpstrDefExt = def_ext[modIF.m_nLastOpenedFilterIX];
    	openDlg.m_ofn.nMaxCustFilter = 0;
    
    	openDlg.m_ofn.Flags |= (OFN_HIDEREADONLY | OFN_PATHMUSTEXIST) ;
    
    
    	if (openDlg.DoModal() == IDOK)
    	   {
    	   CIvfDocument *pIvfDoc = (CIvfDocument *)GetActiveDocument();
    
    	   if (pIvfDoc &&
    	       pIvfDoc->m_eOpenType == CIvfDocument::IVFDOC_OPEN_IMPORT)
    	      pIvfDoc->IvfOnOpenDocumentMessage(openDlg.m_ofn.lpstrFile);
    
    	   else
    	      {
    	      CString newName = openDlg.m_ofn.lpstrFile;
    	      CIVFModDoc *pDoc =
    		   (CIVFModDoc *)modIF.m_DocTemplate->OpenDocumentFile(newName);
    
    	      if (openDlg.m_ofn.nFilterIndex < NUM_EXT_VALS)
    		   modIF.m_nLastOpenedFilterIX = openDlg.m_ofn.nFilterIndex;
    	      }
    	   }
    }
    
    void CMainFrame::OnFileNew() 
    {
    	modIF.m_DocTemplate->OpenDocumentFile(NULL);
    }
    
  5. Unsupported operations


  6. The "File | Info" menu item was removed from the example module because the Inventor handler crashes.

    The original application calls the CIvfApp IvfExitInstance function in the overridden CWinApp ExitInstance function. As the application class is no longer derived from CIvfApp, the IvfExitInstance function is not available. What occurs in IvfExitInstance is unknown, but as the application class is not a CIvfApp this function may no longer be relevent. Any cleanup code required by CWinApp modules should be called from a Remove hook function.


Converting an IRIS Explorer 4.0 CWinApp module

  1. Change the module wrapper type to MFC.
  2. Modify the application class as in the example above.
  3. Replace the mcwMFCInitInstance call in the init hook function with a call to the application class initialization function as above.
  4. Build from the module builder instead of a Visual C++ project. This is optional, but required to compile groups containing the module.