0c9786de3a
MFC needs the entry point to be wWinMainCRTStartup() in Unicode builds but the bakefile-generated projects use the default WinMain() so the sample didn't link in Unicode. Fix this by providing WinMain() which simply forwards to wWinMainCRTStartup() as this seems to work for all MSVC/CRT versions. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@66667 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
411 lines
11 KiB
C++
411 lines
11 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: mfctest.cpp
|
|
// Purpose: Sample to demonstrate mixing MFC and wxWidgets code
|
|
// Author: Julian Smart
|
|
// Id: $Id$
|
|
// Copyright: (c) Julian Smart
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// This sample pops up an initial wxWidgets frame, with a menu item
|
|
// that allows a new MFC window to be created. Note that CDummyWindow
|
|
// is a class that allows a wxWidgets window to be seen as a CWnd
|
|
// for the purposes of specifying a valid main window to the
|
|
// MFC initialisation.
|
|
//
|
|
// You can easily modify this code so that an MFC window pops up
|
|
// initially as the main frame, and allows wxWidgets frames to be
|
|
// created subsequently.
|
|
//
|
|
// (1) Make MyApp::OnInit not create a main window.
|
|
// (2) Make MFC's InitInstance create a main window, and remove
|
|
// creation of CDummyWindow.
|
|
//
|
|
// This can be accomplished by setting START_WITH_MFC_WINDOW to 1 below.
|
|
|
|
#define START_WITH_MFC_WINDOW 0
|
|
|
|
//
|
|
// IMPORTANT NOTES:
|
|
//
|
|
// (1) You may need to set wxUSE_MFC to 1 in include/wx/msw/setup.h but
|
|
// normally this shouldn't be needed any longer, i.e. it works without
|
|
// it for me (VZ)
|
|
//
|
|
// (2) You should link with MFC DLL, not static libraries: or, to use static
|
|
// run-time libraries, use this command for both building wxWidgets and
|
|
// the sample:
|
|
//
|
|
// nmake -f makefile.vc BUILD=debug SHARED=0 DEBUG_RUNTIME_LIBS=0 RUNTIME_LIBS=static all
|
|
//
|
|
// Unless the run-time library settings match for wxWidgets and MFC, you
|
|
// will get link errors for symbols such as __mbctype, __argc, and __argv
|
|
//
|
|
// (3) If you see bogus memory leaks within the MSVC IDE on exit, in this
|
|
// sample or in your own project, you must be using __WXDEBUG__ +
|
|
// WXUSINGDLL + _AFXDLL
|
|
// Unfortunately this confuses the MSVC/MFC leak detector. To do away with
|
|
// these bogus memory leaks, add this to the list of link objects, make it
|
|
// first: mfc[version][u]d.lib
|
|
// - [version] -> 42 or 70 or 80 etc
|
|
// - u if using Unicode
|
|
|
|
#include "stdafx.h"
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#include "wx/evtloop.h"
|
|
|
|
#include "resource.h"
|
|
|
|
#include "mfctest.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// theApp:
|
|
// Just creating this application object runs the whole application.
|
|
//
|
|
CTheApp theApp;
|
|
|
|
// wxWidgets elements
|
|
|
|
// Define a new application type
|
|
class MyApp: public wxApp
|
|
{
|
|
public:
|
|
virtual bool OnInit();
|
|
|
|
// we need to override this as the default behaviour only works when we're
|
|
// running wxWidgets main loop, not MFC one
|
|
virtual void ExitMainLoop();
|
|
|
|
wxFrame *CreateFrame();
|
|
};
|
|
|
|
class MyCanvas: public wxScrolledWindow
|
|
{
|
|
public:
|
|
MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size);
|
|
void OnPaint(wxPaintEvent& event);
|
|
void OnMouseEvent(wxMouseEvent& event);
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
class MyChild: public wxFrame
|
|
{
|
|
public:
|
|
MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style);
|
|
virtual ~MyChild();
|
|
|
|
void OnQuit(wxCommandEvent& event);
|
|
void OnNew(wxCommandEvent& event);
|
|
void OnActivate(wxActivateEvent& event);
|
|
|
|
MyCanvas *canvas;
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
// ID for the menu quit command
|
|
#define HELLO_QUIT 1
|
|
#define HELLO_NEW 2
|
|
|
|
DECLARE_APP(MyApp)
|
|
|
|
// notice use of IMPLEMENT_APP_NO_MAIN() instead of the usual IMPLEMENT_APP!
|
|
IMPLEMENT_APP_NO_MAIN(MyApp)
|
|
|
|
#ifdef _UNICODE
|
|
// In Unicode build MFC normally requires to manually change the entry point to
|
|
// wWinMainCRTStartup() but to avoid having to modify the project options to do
|
|
// it we provide an adapter for it.
|
|
extern "C" int wWinMainCRTStartup();
|
|
|
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, char *, int)
|
|
{
|
|
wWinMainCRTStartup();
|
|
}
|
|
#endif // _UNICODE
|
|
|
|
CMainWindow::CMainWindow()
|
|
{
|
|
LoadAccelTable( wxT("MainAccelTable") );
|
|
Create( NULL, wxT("Hello Foundation Application"),
|
|
WS_OVERLAPPEDWINDOW, rectDefault, NULL, wxT("MainMenu") );
|
|
}
|
|
|
|
void CMainWindow::OnPaint()
|
|
{
|
|
CString s = wxT("Hello, Windows!");
|
|
CPaintDC dc( this );
|
|
CRect rect;
|
|
|
|
GetClientRect( rect );
|
|
dc.SetTextAlign( TA_BASELINE | TA_CENTER );
|
|
dc.SetTextColor( ::GetSysColor( COLOR_WINDOWTEXT ) );
|
|
dc.SetBkMode(TRANSPARENT);
|
|
dc.TextOut( ( rect.right / 2 ), ( rect.bottom / 2 ),
|
|
s, s.GetLength() );
|
|
}
|
|
|
|
void CMainWindow::OnAbout()
|
|
{
|
|
CDialog about( wxT("AboutBox"), this );
|
|
about.DoModal();
|
|
}
|
|
|
|
void CMainWindow::OnTest()
|
|
{
|
|
wxMessageBox(wxT("This is a wxWidgets message box.\nWe're about to create a new wxWidgets frame."), wxT("wxWidgets"), wxOK);
|
|
wxGetApp().CreateFrame();
|
|
}
|
|
|
|
// CMainWindow message map:
|
|
// Associate messages with member functions.
|
|
//
|
|
// It is implied that the ON_WM_PAINT macro expects a member function
|
|
// "void OnPaint()".
|
|
//
|
|
// It is implied that members connected with the ON_COMMAND macro
|
|
// receive no arguments and are void of return type, e.g., "void OnAbout()".
|
|
//
|
|
BEGIN_MESSAGE_MAP( CMainWindow, CFrameWnd )
|
|
//{{AFX_MSG_MAP( CMainWindow )
|
|
ON_WM_PAINT()
|
|
ON_COMMAND( IDM_ABOUT, OnAbout )
|
|
ON_COMMAND( IDM_TEST, OnTest )
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
BOOL CTheApp::InitInstance()
|
|
{
|
|
if ( !CWinApp::InitInstance() )
|
|
return FALSE;
|
|
|
|
// TODO: cmd line parsing
|
|
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
|
|
wxSetInstance(m_hInstance);
|
|
wxApp::m_nCmdShow = m_nCmdShow;
|
|
int argc = 0;
|
|
wxChar **argv = NULL;
|
|
wxEntryStart(argc, argv);
|
|
if ( !wxTheApp || !wxTheApp->CallOnInit() )
|
|
return FALSE;
|
|
|
|
#if START_WITH_MFC_WINDOW
|
|
// Demonstrate creation of an initial MFC main window.
|
|
m_pMainWnd = new CMainWindow();
|
|
m_pMainWnd->ShowWindow( m_nCmdShow );
|
|
m_pMainWnd->UpdateWindow();
|
|
#else
|
|
// Demonstrate creation of an initial wxWidgets main window.
|
|
// Wrap wxWidgets window in a dummy MFC window and
|
|
// make the main window.
|
|
if (wxTheApp && wxTheApp->GetTopWindow())
|
|
{
|
|
m_pMainWnd = new CDummyWindow((HWND) wxTheApp->GetTopWindow()->GetHWND());
|
|
}
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int CTheApp::ExitInstance()
|
|
{
|
|
#if !START_WITH_MFC_WINDOW
|
|
delete m_pMainWnd;
|
|
#endif
|
|
|
|
if ( wxTheApp )
|
|
wxTheApp->OnExit();
|
|
wxEntryCleanup();
|
|
|
|
return CWinApp::ExitInstance();
|
|
}
|
|
|
|
// Override this to provide wxWidgets message loop compatibility
|
|
BOOL CTheApp::PreTranslateMessage(MSG *msg)
|
|
{
|
|
wxEventLoop * const
|
|
evtLoop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
|
|
if ( evtLoop && evtLoop->PreProcessMessage(msg) )
|
|
return TRUE;
|
|
|
|
return CWinApp::PreTranslateMessage(msg);
|
|
}
|
|
|
|
BOOL CTheApp::OnIdle(LONG WXUNUSED(lCount))
|
|
{
|
|
return wxTheApp && wxTheApp->ProcessIdle();
|
|
}
|
|
|
|
/*********************************************************************
|
|
* wxWidgets elements
|
|
********************************************************************/
|
|
|
|
bool MyApp::OnInit()
|
|
{
|
|
if ( !wxApp::OnInit() )
|
|
return false;
|
|
|
|
#if !START_WITH_MFC_WINDOW
|
|
// as we're not inside wxWidgets main loop, the default logic doesn't work
|
|
// in our case and we need to do this explicitly
|
|
SetExitOnFrameDelete(true);
|
|
|
|
(void) CreateFrame();
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
void MyApp::ExitMainLoop()
|
|
{
|
|
// instead of existing wxWidgets main loop, terminate the MFC one
|
|
::PostQuitMessage(0);
|
|
}
|
|
|
|
wxFrame *MyApp::CreateFrame()
|
|
{
|
|
MyChild *subframe = new MyChild(NULL, wxT("Canvas Frame"), wxPoint(10, 10), wxSize(300, 300),
|
|
wxDEFAULT_FRAME_STYLE);
|
|
|
|
subframe->SetTitle(wxT("wxWidgets canvas frame"));
|
|
|
|
// Give it a status line
|
|
subframe->CreateStatusBar();
|
|
|
|
// Make a menubar
|
|
wxMenu *file_menu = new wxMenu;
|
|
|
|
file_menu->Append(HELLO_NEW, wxT("&New MFC Window"));
|
|
file_menu->Append(HELLO_QUIT, wxT("&Close"));
|
|
|
|
wxMenuBar *menu_bar = new wxMenuBar;
|
|
|
|
menu_bar->Append(file_menu, wxT("&File"));
|
|
|
|
// Associate the menu bar with the frame
|
|
subframe->SetMenuBar(menu_bar);
|
|
|
|
int width, height;
|
|
subframe->GetClientSize(&width, &height);
|
|
|
|
MyCanvas *canvas = new MyCanvas(subframe, wxPoint(0, 0), wxSize(width, height));
|
|
canvas->SetCursor(wxCursor(wxCURSOR_PENCIL));
|
|
subframe->canvas = canvas;
|
|
subframe->Show(true);
|
|
|
|
// Return the main frame window
|
|
return subframe;
|
|
}
|
|
|
|
BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
|
|
EVT_PAINT(MyCanvas::OnPaint)
|
|
EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
|
|
END_EVENT_TABLE()
|
|
|
|
// Define a constructor for my canvas
|
|
MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size)
|
|
: wxScrolledWindow(parent, -1, pos, size)
|
|
{
|
|
}
|
|
|
|
// Define the repainting behaviour
|
|
void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
|
|
{
|
|
wxPaintDC dc(this);
|
|
|
|
dc.SetFont(* wxSWISS_FONT);
|
|
dc.SetPen(* wxGREEN_PEN);
|
|
dc.DrawLine(0, 0, 200, 200);
|
|
dc.DrawLine(200, 0, 0, 200);
|
|
|
|
dc.SetBrush(* wxCYAN_BRUSH);
|
|
dc.SetPen(* wxRED_PEN);
|
|
dc.DrawRectangle(100, 100, 100, 50);
|
|
dc.DrawRoundedRectangle(150, 150, 100, 50, 20);
|
|
|
|
dc.DrawEllipse(250, 250, 100, 50);
|
|
dc.DrawLine(50, 230, 200, 230);
|
|
dc.DrawText(wxT("This is a test string"), 50, 230);
|
|
}
|
|
|
|
// This implements a tiny doodling program! Drag the mouse using
|
|
// the left button.
|
|
void MyCanvas::OnMouseEvent(wxMouseEvent& event)
|
|
{
|
|
static long s_xpos = -1;
|
|
static long s_ypos = -1;
|
|
|
|
wxClientDC dc(this);
|
|
dc.SetPen(* wxBLACK_PEN);
|
|
wxPoint pos = event.GetPosition();
|
|
if (s_xpos > -1 && s_ypos > -1 && event.Dragging())
|
|
{
|
|
dc.DrawLine(s_xpos, s_ypos, pos.x, pos.y);
|
|
}
|
|
|
|
s_xpos = pos.x;
|
|
s_ypos = pos.y;
|
|
}
|
|
|
|
BEGIN_EVENT_TABLE(MyChild, wxFrame)
|
|
EVT_MENU(HELLO_QUIT, MyChild::OnQuit)
|
|
EVT_MENU(HELLO_NEW, MyChild::OnNew)
|
|
EVT_ACTIVATE(MyChild::OnActivate)
|
|
END_EVENT_TABLE()
|
|
|
|
MyChild::MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style)
|
|
: wxFrame(frame, -1, title, pos, size, style)
|
|
{
|
|
canvas = NULL;
|
|
}
|
|
|
|
MyChild::~MyChild()
|
|
{
|
|
if ( IsLastBeforeExit() )
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
void MyChild::OnQuit(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
Close(true);
|
|
}
|
|
|
|
void MyChild::OnNew(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
CMainWindow *mainWin = new CMainWindow();
|
|
mainWin->ShowWindow( TRUE );
|
|
mainWin->UpdateWindow();
|
|
}
|
|
|
|
void MyChild::OnActivate(wxActivateEvent& event)
|
|
{
|
|
if (event.GetActive() && canvas)
|
|
canvas->SetFocus();
|
|
}
|
|
|
|
// Dummy MFC window for specifying a valid main window to MFC, using
|
|
// a wxWidgets HWND.
|
|
CDummyWindow::CDummyWindow(HWND hWnd)
|
|
{
|
|
Attach(hWnd);
|
|
}
|
|
|
|
// Don't let the CWnd destructor delete the HWND
|
|
CDummyWindow::~CDummyWindow()
|
|
{
|
|
Detach();
|
|
}
|
|
|