FAQ: Frequently Asked Questions About 16-bit Foundation ClassesID: Q109039
|
---------------------------------------------------------------
The information in this article applies to:
- Microsoft Visual Workbench for Windows, version 1.0
---------------------------------------------------------------
SUMMARY
=======
Microsoft ClassWizard version 1.0 supports deriving classes
only from the classes listed in the Class Type field of the Add
Class dialog box. To create a class derived from a previously
derived class or to derive from another class based on the
Microsoft Foundation Class Library CWnd class that is not
listed in the Class Type field, a few extra steps are required.
MORE INFORMATION
================
For example, suppose the following derivation tree is desired:
MyDerivedClass
^
|
MyBaseClass
^
|
CDialog
or, it is desirable to derive a class from a class based on
CWnd that is not listed in the Class Type field in the Add
Class dialog box, such as CFileDialog. There is no predefined
method to create this type of class hierarchy using the
ClassWizard. However, by using the parsing techniques
ClassWizard uses, you can create these class hierarchies.
The steps below use CDialog as the default class type. Before
proceeding, determine which predefined class type is closest to
the desired base class. For example, CFileDialog is similar to
CDialog. If none of the classes correspond closely to your
desired class, use the generic CWnd class.
To create a class with multiple levels of derivation, perform
the following three steps:
1. Use ClassWizard to create MyDerivedClass, deriving it from
CDialog (or another appropriate predefined class).
2. Use ClassWizard to create MyBaseClass, deriving it from
CDialog (or another appropriate predefined class).
3. Edit the code generated for MyDerivedClass and replace all
references to CDialog with MyBaseClass. This step is very
important; many errors occur if this is not done correctly
and these errors may be difficult to track down.
To create a class based on a class based on CWnd that is not
supported by ClassWizard, perform the following two steps:
1. Use ClassWizard to create MyDerivedClass, deriving it from
CDialog (or another appropriate predefined class based on
CWnd).
2. Edit the code generated for MyDerivedClass and replace all
references to CDialog with the name of the class from which
you are deriving this class, for example, CFileDialog. This
step is very important; many errors occur if this is not
done correctly and these errors may be difficult to track
down.
Then, for either type of class, perform the following three
steps:
1. Delete the project .CLW file.
2. Start App Studio, load your project .RC file, and activate
ClassWizard.
3. Because the project does not have a .CLW file, ClassWizard
prompts to generate a .CLW file. Choose Yes to generate the
file. NOTE: You must generate this file in App Studio. If
you attempt to generate the file in Visual Workbench, VWB
instructs you to generate the file in App Studio.
Once App Studio has created the .CLW file, the base class of
the derived class has been changed successfully. To verify
this, view the class in ClassWizard and see the data in the
Class Info dialog box.
For classes created using multiple levels of derivation, you
can use ClassWizard to pass system messages, such as
WM_INITDIALOG, to the base class as well. To do this, perform
the following nine steps:
1. Start ClassWizard.
2. Select the MyDerivedClass class.
3. Select MyDerivedClass in the Object IDs window.
4. Select the WM_INITDIALOG message in the Messages window.
5. Choose Add Function to add a function skeleton that calls
the OnInitDialog() function in MyBaseClass.
6. Select the MyBaseClass class.
7. Select MyBaseClass in the Object IDs window.
8. Select the WM_INITDIALOG message in the Messages window.
9. Choose Add Function to add a function skeleton that calls
the OnInitDialog() function in CDialog. This step is
required only once. If you derive additional classes from
the base class, you do not need to redo this operation.
Using CFormView in SDI and MDI Applications
---------------------------------------------------------------
The information in this article applies to:
- Microsoft Foundation Class Library for Windows, version 2.0
---------------------------------------------------------------
SUMMARY
=======
The CFormView class provides a convenient method to place
controls into a view that is based on a dialog box template.
The general procedure to use a CFormView is described in the
documentation for the class and is illustrated in the VIEWEX
and CHKBOOK sample applications provided with Microsoft
Foundation Class Library version 2.0. However, these
applications do not demonstrate making the initial size of the
frame window to be the same as the initial size of the form.
In an application that uses the CFormView class, CFormView
replaces the default AppWizard CView class. The documentation
does not demonstrate editing a Visual C++ project to remove the
unneeded CView class and reconstruct the ClassWizard .CLW file.
The text below demonstrates this technique.
The following section lists the steps required to support
creating a single document interface (SDI) or multiple document
interface (MDI) application based on a CFormView, sizing the
initial frame window around the form, changing the style of the
frame, and closing an MDI document using a button in the form.
MORE INFORMATION
================
No fully automated method exists to use a CFormView object in
an application generated by AppWizard. However, the following
nine steps are quite straightforward.
1. Use the AppWizard to generate an SDI or MDI application
skeleton.
2. Design the form (dialog box) in App Studio. Set the styles
according to the CFormView documentation.
3. Use ClassWizard to create a new class based on CFormView.
Either delete the default OK and Cancel buttons, or modify
the ID for these buttons. The values IDOK and IDCANCEL cause
ClassWizard to generate incorrect entries in the message map
and incorrect message handler functions when they are used
in a class derived from CFormView.
4. In the main .CPP file for the application, find the
AddDocTemplate function. Replace the name of the view class
that AppWizard generates with the name of the class derived
from CFormView. Use the #include statement to include the .H
file for the CFormView class.
5. Delete the .CPP and .H files that AppWizard generated to
contain the original CView object. Edit other files in the
project to remove any references to these files.
6. In the Visual Workbench, edit the project to remove
references to the view files deleted in step 5 above.
7. In ClassWizard, choose the deleted view class. ClassWizard
displays its "Repair Class Information" dialog box. Choose
the Remove button to delete the obsolete class from the
project's ClassWizard (.CLW) file.
8. Override the OnUpdate() and UpdateData() member functions as
documented in the CFormView documentation to update the
member variables with the current document data and to
perform dialog data exchange (DDX).
9. If you would like to set the initial size of the form view,
override the OnInitialUpdate() function. The text below
provides additional information about this step, which is
slightly different in an SDI or MDI application.
Changing the Size of an SDI Main Frame Around a CFormView
---------------------------------------------------------
To change the size of the main frame of an SDI application
(that uses CFormView as its view class) to be the appropriate
size for the form you designed in App Studio, override the
OnInitialUpdate() function in your class derived from
CFormView, as follows:
void CMyFormView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit(/*FALSE*/); // default argument is TRUE
}
If the size of the CMyFormView window, before calling
ResizeParentToFit(), is smaller than the size specified in the
dialog box template, and the application overrides the default
TRUE argument in the ResizeParentToFit() function with FALSE,
the following two consequences may occur:
- In the ResizeParentToFit() call, the new size of the parent
window may be calculated based on a form that includes
scroll bars. This takes place if the initial size chosen by
Microsoft Windows is smaller than the form designed in App
Studio.
Because the scroll bars are not needed after changing the
size of the view, the view includes extra unused area on the
right side and at the bottom of the resized form in a width
equal to that of the scroll bars. To work around this
behavior, call ResizeParentToFit() twice; once to "expand"
the view and remove the scroll bars, and the second time to
reduce the size of the view to the smallest size available
without scroll bars. In the second call, the default
bShrinkOnly = TRUE parameter is appropriate.
- The main frame may be too large for the screen if the form
is designed on a system that has a high-resolution monitor
and the code runs on a system that has a standard VGA
resolution.
The ResizeParentToFit() function does not prevent the form from
changing size when the user changes the size of the application
main frame (scroll bars are added automatically if needed). To
modify the style of the frame window that is the parent of a
form view, you can override the PreCreateWindow() function in
the CMainFrame class generated by AppWizard. For example, to
remove the WS_THICKFRAME style and prevent the user from
changing the size of the window, declare PreCreateWindow() in
MAINFRM.H and add the following code to MAINFRM.CPP:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT &cs)
{
cs.style &= ~WS_THICKFRAME;
return CFrameWnd::PreCreateWindow(cs);
}
Changing the Size of an MDI Child Frame Around a CFormView
----------------------------------------------------------
The process of changing the size of an MDI child frame is
similar to changing the size of a main frame for an SDI
application, as explained above. However, the RecalcLayout()
call is not required.
To change the size of an MDI child frame around a form view,
override the OnInitialUpdate() function in your class derived
from CFormView as follows:
void CMDIFormView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
ResizeParentToFit(/*FALSE*/); // default argument is TRUE
}
If the application overrides the default argument to the
ResizeParentToFit() function, essentially the same consequences
occur as for an SDI application, as explained above. In
addition, the child window may be too large for the enclosing
MDI main frame or for the entire screen.
To change the style of the MDI child frame (for example, to
remove the WS_THICKFRAME style so the user cannot change the
size of the window), derive an MDI child window class and
override the PreCreateWindow function as demonstrated in the
SDI example above.
Closing an MDI Form with a Button
---------------------------------
To create a button on a form that closes the document, use
ClassWizard to add a message handler for the BN_CLICKED message
to the CFormView class. Make sure that the buttons in CFormView
do not have the default IDOK or IDCANCEL identifiers. If they
do, ClassWizard creates incorrect entries in the message map
and incorrect functions for the buttons.
Once the message handler is in place, you can simulate the
Close command on the File menu with the following code:
void CMyForm::OnClickedButton1()
{
PostMessage(WM_COMMAND, ID_FILE_CLOSE);
}
This method to close a form prompts the user to save the file
if the IsModified() member function associated with the
document returns TRUE.
class CMyView : public CScrollView
IMPLEMENT_DYNCREATE(CMyView, CScrollView)
changing the BEGIN_MESSAGE_MAP as follows
BEGIN_MESSAGE_MAP(CMyView, CScrollView)
and changing any other references to CView to CScrollView.Q99562 Switching views in a Single Document Interface Program
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_nCmdShow = SW_SHOWMAXIMIZED; // ADD THIS LINE!
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
m_pMainWnd = pMainFrame;
In an SDI application, in the CWinApp::InitInstance() function,
set CWinApp::m_nCmdShow to SW_SHOWMAXIMIZED before calling
OnFileNew(). For example, in an application generated by AppWizard,
the code is as follows:
m_nCmdShow = SW_SHOWMAXIMIZED;
// create a new (empty) document
OnFileNew();
Changing Window Background Color with Foundation Classes
---------------------------------------------------------------
The information in this article applies to:
- Microsoft Foundation Classes for Windows, version 2.0
---------------------------------------------------------------
SUMMARY
=======
To change the background color for a CView, CFrameWnd, or CWnd
object, process the WM_ERASEBKGND message. The text below
demonstrates doing this.
BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
{
// Set brush to desired background color
CBrush backBrush(RGB(255, 128, 128));
// Save old brush
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect); // Erase the area needed
pDC->PatBlt(rect.left, rect.top, rect.Width(),
rect.Height(), PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
MORE INFORMATION
================
To change the background color of a CFormView object, either
process the WM_ERASEBKGND message and use the code above or
process the WM_CTLCOLOR message to change the background color.
For more information on changing the background color of a
dialog box by processing the WM_CTLCOLOR message, please search
in the Microsoft Knowledge Base on the following words:
Changing Background Color MFC
afx_msg void OnUpdatePage(CCmdUI *pCmdUI);
Add the following to the application message map:
ON_UPDATE_COMMAND_UI(ID_INDICATOR_PAGE, OnUpdatePage)
Add the following to a source code file (probably MAINFRM.CPP):
void CMainFrame::OnUpdatePage(CCmdUI *pCmdUI)
{
pCmdUI->Enable();
}
To display text in the panes, either call SetPaneText() or
call CCmdUI::SetText() in the OnUpdate() function. For
example, you might want to set up an integer variable m_nPage
that contains the current page number. Then, the OnUpdatePage()
function might read as follows:
void CMainFrame::OnUpdatePage(CCmdUI *pCmdUI)
{
pCmdUI->Enable();
char szPage[16];
wsprintf((LPSTR)szPage, "Page %d", m_nPage);
pCmdUI->SetText((LPSTR)szPage);
}
This technique causes the page number to appear in the pane
during idle processing in the same manner that the application
updates other indicators.
Q99198 Displaying the Current Time in a CStatusBar Pane
Using the C Run-Time WEP() in an MFC 2.0 _USRDLL Library
---------------------------------------------------------------
The information in this article applies to:
- Microsoft Foundation Class Library for Windows, version 2.0
---------------------------------------------------------------
SUMMARY
=======
In a dynamic-link library (DLL) built with Microsoft Foundation
Class Library version 2.0, the _USRDLL model uses the WEP()
(Windows exit procedure) function provided in the C run-time
library. Because the code uses the C library WEP() function,
the destructors for static and global objects in the DLL are
called and the CWinApp::ExitInstance() function for the DLL
application object is called.
MORE INFORMATION
================
To use the WEP() function in the C run-time library, the DLL
must export WEP in its module definition (.DEF) file. To do so,
add the following statement to the .DEF file:
EXPORTS
WEP @1 RESIDENTNAME
While the ordinal number you choose is not important, you must
specify the RESIDENTNAME attribute when you export WEP(). Do
not include a WEP() function in the DLL code. If you do,
Windows calls that function instead of the C library WEP() and
the destructors for global objects and static objects, and
CWinApp::ExitInstance() are not called.
If you DLL must contain clean-up code, overload the
ExitInstance() function. If your DLL uses an import library to
link to another DLL developed with the Microsoft Foundation
Classes, be sure to list the Microsoft Foundation Class Library
and the C run-time library before the import library for the
other DLL. This step ensures that the linker includes the WEP()
in the C run-time library instead of linking in a reference to
the WEP() in the other DLL.
The instructions above describe building a _USRDLL that unloads
itself and cleans up properly. The text below describes the
process that occurs when a DLL cleans up.
When Windows unloads the DLL, it calls the WEP() function in
the DLL, which, using the procedure above, is the WEP()
function in the C run-time library. WEP() calls the _WEP()
function implemented in the Microsoft Foundation Class Library.
The _WEP() function calls CWinApp::ExitInstance(). When
ExitInstance() and _WEP() return, the WEP function calls the
destructors for any static or global objects in the DLL.
For more information about using the C run-time library WEP()
function in an _USRDLL, please refer to Technical Note 11:
"Using MFC as Part of a DLL" in the MFC Tech Notes help file
distributed with Visual C++ version 1.0.
#define new DEBUG_NEW
Once this directive is in place, the preprocessor replaces all
occurrences of new with DEBUG_NEW and the Microsoft Foundation
Class Library handles the remainder of the processing. When you
compile a release version of your application, DEBUG_NEW
reverts to the new operator and eliminates the filename and
line number overhead.
char *p;
p = new char[1];
and define DEBUG_NEW at the beginning of the file. Compile the
application for debugging mode. When you exit the application,
it displays text such as the following on your debugging
terminal or in the DBWIN window:
Detected memory leaks!
Dumping objects ->
{5} c:\msvc\mfc\samples\helloapp\helloapp.cpp(34) :
non-object block at $45CF3Eg
Object dump complete.
Line 34 is the line that contains the new operator.
[Diagnostics]
TraceEnabled = 1
TraceFlags = 0
As long as TraceEnabled is set to 1, tracing is enabled.
Changing Window Attributes in an MFC Application
---------------------------------------------------------------
The information in this article applies to:
- Microsoft Foundation Class Library for Windows, version 2.0
---------------------------------------------------------------
SUMMARY
=======
To change the default window attributes used by a framework
application created in AppWizard, override the window's
PreCreateWindow() virtual member function. PreCreateWindow()
allows an application to access the creation process normally
processed internally by the CDocTemplate class. The framework
calls PreCreateWindow() just prior to creating the window. By
modifying the CREATESTRUCT structure parameter to
PreCreateWindow(), your application can change the attributes
used to create the window.
The CTRLBARS sample application, provided with the Microsoft
Foundation Class Library version 2.0, demonstrates this
technique to change window attributes. Note that depending on
what your application changes in PreCreateWindow(), it may be
necessary to call the base class implementation.
MORE INFORMATION
================
In a single document interface (SDI) application, the default
window style in the framework is a combination of the
WS_OVERLAPPEDWINDOW and FWS_ADDTOTITLE styles. FWS_ADDTOTITLE
is a framework-specific style that instructs the framework to
add the document title to the window's caption. To change the
window attributes in an SDI application, override the
PreCreateWindow() function in your class derived form
CFrameWnd. For example:
BOOL CMainFrame::PreCreateWindow(CREATESTRUt& cs)
{
// Create a window without
// min/max buttons or sizable border
cs.style = WS_OVERLAPPED | WS_SYSMENU | WS_BORDER;
// Size the window to 1/3 screen size and center it
cs.cy = ::GetSystemMetrics(SM_CYSCREEN) / 3;
cs.cx = ::GetSystemMetrics(SM_CXSCREEN) / 3;
cs.y = ((cs.cy * 3) - cs.cy) / 2;
cs.x = ((cs.cx * 3) - cs.cx) / 2;
return CFrameWnd::PreCreateWindow(cs);
}
A little more work is required to change the window style of a
child window in a multiple document interface (MDI)
application. By default, an MDI application generated in
AppWizard uses the default CMDIChildWnd class defined in the
Microsoft Foundation Class Library. To change the window style
of an MDI child window, your application must derive a new
class from CMDIChildWnd and replace all references to
CMDIChildWnd in your project with references to the new class.
Most likely, the only reference to CMDIChildWnd in the
application is located in your application's InitInstance()
member function.
The default window style used in an MDI application is a
combination of the WS_CHILD, WS_OVERLAPPEDWINDOW, and
FWS_ADDTOTITLE styles. To change the window attributes of an
MDI application's child windows, override the PreCreateWindow()
function in your class derived from CMDIChildWnd. For example:
BOOL CMyChildWnd::PreCreateWindow(CREATESTRUCT& cs)
{
// Create a child window without the maximize button
cs.style &= ~WS_MAXIMIZEBOX;
return CMDIChildWnd::PreCreateWindow(cs);
}
For more information about the PreCreateWindow() function,
please refer to the Microsoft Visual C++ "Class Library
Reference, Volume 1" or to the Visual C++ Help file.
MyEditCtrlPtr = (CEdit *)GetDlgItem(IDC_MYEDITCTRL);
Background Processing In an MFC Application
---------------------------------------------------------------
The information in this article applies to:
- Microsoft Foundation Class Library for Windows, version 2.0
---------------------------------------------------------------
SUMMARY
=======
Many applications perform lengthy processing "in the
background" during intervals that the user is not otherwise
interacting with the application. In an application developed
for the Microsoft Windows operating system, an application can
perform background processing by splitting a lengthy process
into many small fragments. After processing each fragment, the
application yields execution control to Windows using a
PeekMessage() loop.
An application developed with the Microsoft Foundation Class
Library can perform background processing either by using the
PeekMessage() loop in the library code's main message loop or
by embedding another PeekMessage() loop in the application.
MORE INFORMATION
================
In an application developed with the Microsoft Foundation Class
Library, the main message loop in the CWinApp class contains a
PeekMessage() loop. This loop calls the CWinApp::OnIdle()
function between messages. An application can process messages
in this idle time by overriding the OnIdle() function. For more
information about performing background processing in the
OnIdle() function, please refer to the documentation for the
CWinApp::OnIdle() function in the "Class Libraries Reference"
manual.
Another method to perform background processing in an
application involves embedding a PeekMessage() loop in a
function. Because a PeekMessage() loop is very similar to the
main message loop, such a loop in an application developed with
the Microsoft Foundation Class Library must perform many of the
functions of the main message loop in the library. The
following code fragment demonstrates writing a PeekMessage()
loop that is compatible with the Microsoft Foundation Class
Library:
while (bDoingBackgroundProcessing)
{
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
bDoingBackgroundProcessing = FALSE;
::PostQuitMessage();
break;
}
if (!AfxGetApp()->PreTranslateMessage(&msg))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
AfxGetApp()->OnIdle(0); // updates user interface
AfxGetApp()->OnIdle(1); // frees temporary objects
// Perform some background processing here
}
Additional query words: qa q a faq 2.00 2.50
Keywords : kbprg kb16bitonly kbnokeyword kbMFC kbVC
Version : 1.0 1.5
Platform : WINDOWS
Issue type : kbinfo
Last Reviewed: July 14, 1999