- Replace CWinApp with cxModuleApp
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);
}
- Modify Frame Class
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;
}
- Add message handlers from application class to Document class
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();
}
- Create module resources and interface code
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
- Put it all together
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.
- Converting the application class
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;
}
- Moving the message handlers
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);
}
- Unsupported operations
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.