Microsoft Foundation Classes Piotr Janczyk
Co to jest MFC? Jest to podstawowa biblioteka Visual C++, której klasy stanowią szkielet aplikacji dla programów pracujących w systemie Windows. Napisane w języku C++ klasy zawierają bardzo dużo kodu potrzebnego do zarządzania oknami, elementami menu i dialogami; zapewniają podstawowe operacje wejścia/wyjścia i dostarczają gotowe struktury danych: listy, kolekcje itp. Historia: MFC powstała ponad 10 lat temu razem z pojawieniem się Visual C++ 1.0. Od wersji 3.0, aż do obecnej ( 6.0 ) MFC jest biblioteką 32 bitową, poprzednie wersje były 16 bitowe (1.0-2.5). Ze względu na szybko zmieniające się wersje biblioteki, Microsoft zdecydował od wersji 4.2 wprowadzić zgodność ze wszystkimi kolejnymi wersjami. Od tego czasu uaktualnienia biblioteki skompilowane są do pliku MFC42.DLL. Typowe funkcje używane przez Visual C++ zawarte są w bibliotece MSVCRT.DLL, nie są to jednak funkcje biblioteki MFC, co jest często mylone, gdyż obydwa te pliki są potrzebne do prawidłowego działania aplikacji korzystających z MFC. 2
Przykłady aplikacji: SDI Oparta o okienko dialogowe WIN32 Console Application with MFC support MDI Wykorzystując MFC możemy tworzyć ponadto: 1. Kontrolki ActiveX 2. Static Libraries 3. Dynamic-Link Libraries 3
Cechy charakterystyczne: Architektura dokument/widok Technika programowania, w której dane programu (model) oraz interfejs użytkownika są rozdzielone. Zrozumienie tej techniki oraz jej implementacji w MFC jest niewątpliwie konieczne w przypadku programistów zamierzających korzystać z dobrodziejstw oferowanych przez tą bibliotekę. Wśród korzyści wypływających ze stosowania tej techniki trudno przecenić ułatwienie pielęgnacji programu, dzięki wyraźnemu rozgraniczeniu merytorycznej części programu od interfejsu użytkownika. Mapa komunikatów BEGIN_MESSAGE_MAP(CTramView, CScrollView) //AFX_MSG_MAP(CTramView) ON_WM_LBUTTONDOWN() ON_WM_SETCURSOR() ON_WM_LBUTTONDBLCLK() ON_WM_CONTEXTMENU() ON_COMMAND(ID_EDIT_CLEAR, OnEditClear) ON_COMMAND(ID_STATION_PROPERTIES, OnStationProperties) ON_COMMAND(ID_START_SIMULATION, OnStartSimulation) ON_COMMAND(ID_STATION_BEGIN_LINE, OnStationBeginLine) ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() Kolekcje o Biblioteka MFC udostępnia różnego rodzaju kolekcje, które są podobne i równie efektywne jak te z STL: CList (CObList... ) CArray CStringList CMap... 4
Serializacja klas o Jest to bardzo prosty i wygodny sposób zapisywania zawartości całych obiektów klas do pliku lub czegoś innego (drukarka, urządzenia zewnętrzne, itp.). Pisanie aplikacji w Visual C++ Jeżeli budujemy projekt oparty na bibliotece MFC, możemy efektywnie automatyzować proces pisania kodu. Podstawową pomocą w tej czynności jest ClassWizard y : tworzenie okienek, łączenie zdarzeń razem z funkcjami, itp.. Biblioteka zawiera wiele funkcji wspierających debugowanie: o TRACE o ASSERT o Detekcja wycieków pamięci: CMemoryState z metodami: CheckPoint 5
Difference DumpStatistics I wiele innych Przykładowy program: Plik MFC.H #include "resource.h" // main symbols class CMfcApp : public CWinApp public: CMfcApp(); virtual BOOL InitInstance(); DECLARE_MESSAGE_MAP() }; Plik MFC.CPP #include "stdafx.h" #include "mfc.h" BEGIN_MESSAGE_MAP(CMfcApp, CWinApp) //AFX_MSG_MAP(CMfcApp) //}}AFX_MSG_MAP ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) END_MESSAGE_MAP() CMfcApp::CMfcApp() } CMfcApp theapp; BOOL CMfcApp::InitInstance() CMultiDocTemplate* pdoctemplate; pdoctemplate = new CMultiDocTemplate( IDR_MFC1TYPE, RUNTIME_CLASS(CDocument), RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CView)); AddDocTemplate(pDocTemplate); CMDIFrameWnd* pmainframe = new CMDIFrameWnd; if (!pmainframe->loadframe(idr_mainframe)) return FALSE; m_pmainwnd = pmainframe; 6
CCommandLineInfo cmdinfo; ParseCommandLine(cmdInfo); if (!ProcessShellCommand(cmdInfo)) return FALSE; pmainframe->showwindow(m_ncmdshow); pmainframe->updatewindow(); } return TRUE; Funkcja WinMain zaszyta wewnątrz biblioteki: ///////////////////////////////////////////////////////////////////////////// // Standard WinMain implementation // Can be replaced as long as 'AfxWinInit' is called first int AFXAPI AfxWinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPTSTR lpcmdline, int ncmdshow) ASSERT(hPrevInstance == NULL); int nreturncode = -1; CWinThread* pthread = AfxGetThread(); CWinApp* papp = AfxGetApp(); // AFX internal initialization if (!AfxWinInit(hInstance, hprevinstance, lpcmdline, ncmdshow)) goto InitFailure; // App global initializations (rare) if (papp!= NULL &&!papp->initapplication()) goto InitFailure; // Perform specific initializations if (!pthread->initinstance()) if (pthread->m_pmainwnd!= NULL) TRACE0("Warning: Destroying non-null m_pmainwnd\n"); pthread->m_pmainwnd->destroywindow(); } nreturncode = pthread->exitinstance(); goto InitFailure; } nreturncode = pthread->run(); InitFailure: #ifdef _DEBUG // Check for missing AfxLockTempMap calls if (AfxGetModuleThreadState()->m_nTempMapLock!= 0) TRACE1("Warning: Temp map lock count non-zero (%ld).\n", 7
AfxGetModuleThreadState()->m_nTempMapLock); } AfxLockTempMaps(); AfxUnlockTempMaps(-1); #endif AfxWinTerm(); return nreturncode; } Kompilacja programu: Przykładowy plik konfiguracyjny MAKEFILE wygenerowany przez Visual C++. # Microsoft Developer Studio Generated NMAKE File, Based on MFC.dsp CFG=MFC - Win32 Release!IF "$(OS)" == "Windows_NT" NULL=!ELSE NULL=nul!ENDIF CPP=cl.exe RSC=rc.exe OUTDIR=.\Release INTDIR=.\Release # Begin Custom Macros OutDir=.\Release # End Custom Macros ALL : "$(OUTDIR)\MFC.exe" "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "_AFXDLL" /Fp"$(INTDIR)\MFC.pch" /Yu"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c RSC_PROJ=/l 0x415 /fo"$(intdir)\mfc.res" /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe BSC32_FLAGS=/nologo /o"$(outdir)\mfc.bsc" BSC32_SBRS= \ LINK32=link.exe LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(outdir)\mfc.pdb" /machine:i386 /out:"$(outdir)\mfc.exe" LINK32_OBJS= \ "$(INTDIR)\MFC.obj" \ "$(INTDIR)\StdAfx.obj" \ "$(INTDIR)\MFC.res" 8
"$(OUTDIR)\MFC.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @ $(LINK32_FLAGS) $(LINK32_OBJS).c$(INTDIR)}.obj:: $(CPP) @.cpp$(intdir)}.obj:: $(CPP) @.cxx$(intdir)}.obj:: $(CPP) @.c$(intdir)}.sbr:: $(CPP) @.cpp$(intdir)}.sbr:: $(CPP) @.cxx$(intdir)}.sbr:: $(CPP) @ SOURCE=.\MFC.cpp "$(INTDIR)\MFC.obj" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\MFC.pch" SOURCE=.\MFC.rc "$(INTDIR)\MFC.res" : $(SOURCE) "$(INTDIR)" $(RSC) $(RSC_PROJ) $(SOURCE) SOURCE=.\StdAfx.cpp CPP_SWITCHES=/nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "_AFXDLL" /Fp"$(INTDIR)\MFC.pch" /Yc"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 9
"$(INTDIR)\StdAfx.obj" "$(INTDIR)\MFC.pch" : $(SOURCE) "$(INTDIR)" $(CPP) @ $(CPP_SWITCHES) $(SOURCE) Ustawienia do kompilacji: Ustawieni a konsolidac ji: 10
Alternatywa dla MFC: Inprise stworzył bibliotekę VCL (Visual Component Library), pozwalającą na bardzo prostą obsługę graficznych elementów aplikacji oraz okien dialogowych. Większa część bibliotek VCL została napisana w obiektowym Pascalu. Można również posłużyć się bibliotekami OWL (Object Windows Library) wykorzystywanymi w poprzednich wersjach kompilatorów Borlanda. Innowacją wprowadzoną do najnowszej wersji jest wsparcie dla bibliotek MFC, dzięki któremu możliwe jest łączenie projektów pochodzących ze środowiska Visual C++ Microsoftu z projektami tworzonymi w pakiecie firmy Inprise. 11