Fix entry point in Unicode build of the MFC sample.
[wxWidgets.git] / samples / mfc / mfctest.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mfctest.cpp
3 // Purpose: Sample to demonstrate mixing MFC and wxWidgets code
4 // Author: Julian Smart
5 // Id: $Id$
6 // Copyright: (c) Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // This sample pops up an initial wxWidgets frame, with a menu item
11 // that allows a new MFC window to be created. Note that CDummyWindow
12 // is a class that allows a wxWidgets window to be seen as a CWnd
13 // for the purposes of specifying a valid main window to the
14 // MFC initialisation.
15 //
16 // You can easily modify this code so that an MFC window pops up
17 // initially as the main frame, and allows wxWidgets frames to be
18 // created subsequently.
19 //
20 // (1) Make MyApp::OnInit not create a main window.
21 // (2) Make MFC's InitInstance create a main window, and remove
22 // creation of CDummyWindow.
23 //
24 // This can be accomplished by setting START_WITH_MFC_WINDOW to 1 below.
25
26 #define START_WITH_MFC_WINDOW 0
27
28 //
29 // IMPORTANT NOTES:
30 //
31 // (1) You may need to set wxUSE_MFC to 1 in include/wx/msw/setup.h but
32 // normally this shouldn't be needed any longer, i.e. it works without
33 // it for me (VZ)
34 //
35 // (2) You should link with MFC DLL, not static libraries: or, to use static
36 // run-time libraries, use this command for both building wxWidgets and
37 // the sample:
38 //
39 // nmake -f makefile.vc BUILD=debug SHARED=0 DEBUG_RUNTIME_LIBS=0 RUNTIME_LIBS=static all
40 //
41 // Unless the run-time library settings match for wxWidgets and MFC, you
42 // will get link errors for symbols such as __mbctype, __argc, and __argv
43 //
44 // (3) If you see bogus memory leaks within the MSVC IDE on exit, in this
45 // sample or in your own project, you must be using __WXDEBUG__ +
46 // WXUSINGDLL + _AFXDLL
47 // Unfortunately this confuses the MSVC/MFC leak detector. To do away with
48 // these bogus memory leaks, add this to the list of link objects, make it
49 // first: mfc[version][u]d.lib
50 // - [version] -> 42 or 70 or 80 etc
51 // - u if using Unicode
52
53 #include "stdafx.h"
54
55 // For compilers that support precompilation, includes "wx/wx.h".
56 #include "wx/wxprec.h"
57
58 #ifdef __BORLANDC__
59 #pragma hdrstop
60 #endif
61
62 #ifndef WX_PRECOMP
63 #include "wx/wx.h"
64 #endif
65
66 #include "wx/evtloop.h"
67
68 #include "resource.h"
69
70 #include "mfctest.h"
71
72 /////////////////////////////////////////////////////////////////////////////
73
74 // theApp:
75 // Just creating this application object runs the whole application.
76 //
77 CTheApp theApp;
78
79 // wxWidgets elements
80
81 // Define a new application type
82 class MyApp: public wxApp
83 {
84 public:
85 virtual bool OnInit();
86
87 // we need to override this as the default behaviour only works when we're
88 // running wxWidgets main loop, not MFC one
89 virtual void ExitMainLoop();
90
91 wxFrame *CreateFrame();
92 };
93
94 class MyCanvas: public wxScrolledWindow
95 {
96 public:
97 MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size);
98 void OnPaint(wxPaintEvent& event);
99 void OnMouseEvent(wxMouseEvent& event);
100 DECLARE_EVENT_TABLE()
101 };
102
103 class MyChild: public wxFrame
104 {
105 public:
106 MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style);
107 virtual ~MyChild();
108
109 void OnQuit(wxCommandEvent& event);
110 void OnNew(wxCommandEvent& event);
111 void OnActivate(wxActivateEvent& event);
112
113 MyCanvas *canvas;
114
115 DECLARE_EVENT_TABLE()
116 };
117
118 // ID for the menu quit command
119 #define HELLO_QUIT 1
120 #define HELLO_NEW 2
121
122 DECLARE_APP(MyApp)
123
124 // notice use of IMPLEMENT_APP_NO_MAIN() instead of the usual IMPLEMENT_APP!
125 IMPLEMENT_APP_NO_MAIN(MyApp)
126
127 #ifdef _UNICODE
128 // In Unicode build MFC normally requires to manually change the entry point to
129 // wWinMainCRTStartup() but to avoid having to modify the project options to do
130 // it we provide an adapter for it.
131 extern "C" int wWinMainCRTStartup();
132
133 int WINAPI WinMain(HINSTANCE, HINSTANCE, char *, int)
134 {
135 wWinMainCRTStartup();
136 }
137 #endif // _UNICODE
138
139 CMainWindow::CMainWindow()
140 {
141 LoadAccelTable( wxT("MainAccelTable") );
142 Create( NULL, wxT("Hello Foundation Application"),
143 WS_OVERLAPPEDWINDOW, rectDefault, NULL, wxT("MainMenu") );
144 }
145
146 void CMainWindow::OnPaint()
147 {
148 CString s = wxT("Hello, Windows!");
149 CPaintDC dc( this );
150 CRect rect;
151
152 GetClientRect( rect );
153 dc.SetTextAlign( TA_BASELINE | TA_CENTER );
154 dc.SetTextColor( ::GetSysColor( COLOR_WINDOWTEXT ) );
155 dc.SetBkMode(TRANSPARENT);
156 dc.TextOut( ( rect.right / 2 ), ( rect.bottom / 2 ),
157 s, s.GetLength() );
158 }
159
160 void CMainWindow::OnAbout()
161 {
162 CDialog about( wxT("AboutBox"), this );
163 about.DoModal();
164 }
165
166 void CMainWindow::OnTest()
167 {
168 wxMessageBox(wxT("This is a wxWidgets message box.\nWe're about to create a new wxWidgets frame."), wxT("wxWidgets"), wxOK);
169 wxGetApp().CreateFrame();
170 }
171
172 // CMainWindow message map:
173 // Associate messages with member functions.
174 //
175 // It is implied that the ON_WM_PAINT macro expects a member function
176 // "void OnPaint()".
177 //
178 // It is implied that members connected with the ON_COMMAND macro
179 // receive no arguments and are void of return type, e.g., "void OnAbout()".
180 //
181 BEGIN_MESSAGE_MAP( CMainWindow, CFrameWnd )
182 //{{AFX_MSG_MAP( CMainWindow )
183 ON_WM_PAINT()
184 ON_COMMAND( IDM_ABOUT, OnAbout )
185 ON_COMMAND( IDM_TEST, OnTest )
186 //}}AFX_MSG_MAP
187 END_MESSAGE_MAP()
188
189 BOOL CTheApp::InitInstance()
190 {
191 if ( !CWinApp::InitInstance() )
192 return FALSE;
193
194 // TODO: cmd line parsing
195 WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
196 wxSetInstance(m_hInstance);
197 wxApp::m_nCmdShow = m_nCmdShow;
198 int argc = 0;
199 wxChar **argv = NULL;
200 wxEntryStart(argc, argv);
201 if ( !wxTheApp || !wxTheApp->CallOnInit() )
202 return FALSE;
203
204 #if START_WITH_MFC_WINDOW
205 // Demonstrate creation of an initial MFC main window.
206 m_pMainWnd = new CMainWindow();
207 m_pMainWnd->ShowWindow( m_nCmdShow );
208 m_pMainWnd->UpdateWindow();
209 #else
210 // Demonstrate creation of an initial wxWidgets main window.
211 // Wrap wxWidgets window in a dummy MFC window and
212 // make the main window.
213 if (wxTheApp && wxTheApp->GetTopWindow())
214 {
215 m_pMainWnd = new CDummyWindow((HWND) wxTheApp->GetTopWindow()->GetHWND());
216 }
217 #endif
218
219 return TRUE;
220 }
221
222 int CTheApp::ExitInstance()
223 {
224 #if !START_WITH_MFC_WINDOW
225 delete m_pMainWnd;
226 #endif
227
228 if ( wxTheApp )
229 wxTheApp->OnExit();
230 wxEntryCleanup();
231
232 return CWinApp::ExitInstance();
233 }
234
235 // Override this to provide wxWidgets message loop compatibility
236 BOOL CTheApp::PreTranslateMessage(MSG *msg)
237 {
238 wxEventLoop * const
239 evtLoop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
240 if ( evtLoop && evtLoop->PreProcessMessage(msg) )
241 return TRUE;
242
243 return CWinApp::PreTranslateMessage(msg);
244 }
245
246 BOOL CTheApp::OnIdle(LONG WXUNUSED(lCount))
247 {
248 return wxTheApp && wxTheApp->ProcessIdle();
249 }
250
251 /*********************************************************************
252 * wxWidgets elements
253 ********************************************************************/
254
255 bool MyApp::OnInit()
256 {
257 if ( !wxApp::OnInit() )
258 return false;
259
260 #if !START_WITH_MFC_WINDOW
261 // as we're not inside wxWidgets main loop, the default logic doesn't work
262 // in our case and we need to do this explicitly
263 SetExitOnFrameDelete(true);
264
265 (void) CreateFrame();
266 #endif
267
268 return true;
269 }
270
271 void MyApp::ExitMainLoop()
272 {
273 // instead of existing wxWidgets main loop, terminate the MFC one
274 ::PostQuitMessage(0);
275 }
276
277 wxFrame *MyApp::CreateFrame()
278 {
279 MyChild *subframe = new MyChild(NULL, wxT("Canvas Frame"), wxPoint(10, 10), wxSize(300, 300),
280 wxDEFAULT_FRAME_STYLE);
281
282 subframe->SetTitle(wxT("wxWidgets canvas frame"));
283
284 // Give it a status line
285 subframe->CreateStatusBar();
286
287 // Make a menubar
288 wxMenu *file_menu = new wxMenu;
289
290 file_menu->Append(HELLO_NEW, wxT("&New MFC Window"));
291 file_menu->Append(HELLO_QUIT, wxT("&Close"));
292
293 wxMenuBar *menu_bar = new wxMenuBar;
294
295 menu_bar->Append(file_menu, wxT("&File"));
296
297 // Associate the menu bar with the frame
298 subframe->SetMenuBar(menu_bar);
299
300 int width, height;
301 subframe->GetClientSize(&width, &height);
302
303 MyCanvas *canvas = new MyCanvas(subframe, wxPoint(0, 0), wxSize(width, height));
304 canvas->SetCursor(wxCursor(wxCURSOR_PENCIL));
305 subframe->canvas = canvas;
306 subframe->Show(true);
307
308 // Return the main frame window
309 return subframe;
310 }
311
312 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
313 EVT_PAINT(MyCanvas::OnPaint)
314 EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
315 END_EVENT_TABLE()
316
317 // Define a constructor for my canvas
318 MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size)
319 : wxScrolledWindow(parent, -1, pos, size)
320 {
321 }
322
323 // Define the repainting behaviour
324 void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
325 {
326 wxPaintDC dc(this);
327
328 dc.SetFont(* wxSWISS_FONT);
329 dc.SetPen(* wxGREEN_PEN);
330 dc.DrawLine(0, 0, 200, 200);
331 dc.DrawLine(200, 0, 0, 200);
332
333 dc.SetBrush(* wxCYAN_BRUSH);
334 dc.SetPen(* wxRED_PEN);
335 dc.DrawRectangle(100, 100, 100, 50);
336 dc.DrawRoundedRectangle(150, 150, 100, 50, 20);
337
338 dc.DrawEllipse(250, 250, 100, 50);
339 dc.DrawLine(50, 230, 200, 230);
340 dc.DrawText(wxT("This is a test string"), 50, 230);
341 }
342
343 // This implements a tiny doodling program! Drag the mouse using
344 // the left button.
345 void MyCanvas::OnMouseEvent(wxMouseEvent& event)
346 {
347 static long s_xpos = -1;
348 static long s_ypos = -1;
349
350 wxClientDC dc(this);
351 dc.SetPen(* wxBLACK_PEN);
352 wxPoint pos = event.GetPosition();
353 if (s_xpos > -1 && s_ypos > -1 && event.Dragging())
354 {
355 dc.DrawLine(s_xpos, s_ypos, pos.x, pos.y);
356 }
357
358 s_xpos = pos.x;
359 s_ypos = pos.y;
360 }
361
362 BEGIN_EVENT_TABLE(MyChild, wxFrame)
363 EVT_MENU(HELLO_QUIT, MyChild::OnQuit)
364 EVT_MENU(HELLO_NEW, MyChild::OnNew)
365 EVT_ACTIVATE(MyChild::OnActivate)
366 END_EVENT_TABLE()
367
368 MyChild::MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style)
369 : wxFrame(frame, -1, title, pos, size, style)
370 {
371 canvas = NULL;
372 }
373
374 MyChild::~MyChild()
375 {
376 if ( IsLastBeforeExit() )
377 PostQuitMessage(0);
378 }
379
380 void MyChild::OnQuit(wxCommandEvent& WXUNUSED(event))
381 {
382 Close(true);
383 }
384
385 void MyChild::OnNew(wxCommandEvent& WXUNUSED(event))
386 {
387 CMainWindow *mainWin = new CMainWindow();
388 mainWin->ShowWindow( TRUE );
389 mainWin->UpdateWindow();
390 }
391
392 void MyChild::OnActivate(wxActivateEvent& event)
393 {
394 if (event.GetActive() && canvas)
395 canvas->SetFocus();
396 }
397
398 // Dummy MFC window for specifying a valid main window to MFC, using
399 // a wxWidgets HWND.
400 CDummyWindow::CDummyWindow(HWND hWnd)
401 {
402 Attach(hWnd);
403 }
404
405 // Don't let the CWnd destructor delete the HWND
406 CDummyWindow::~CDummyWindow()
407 {
408 Detach();
409 }
410