Changes from MFC Versions 3.x
This article describes the most common problems that can occur when porting an application written with MFC 3.x (the MFC included with Visual C++ 2.x) to MFC 4.x. The following porting issues are discussed:
- Window classes are no longer pre-registered by MFC.
- CWinApp::m_templateList no longer exists.
- CRuntimeClass::m_pfnConstruct is now m_pfnCreateObject.
- Changes in CStatusBar and CToolBar implementation can break previous code.
- Changes in CPropertySheet implementation can break previous code.
- CPropertySheet always changes its font to the default font.
- Do property sheet modifications in OnInitDialog after a call to the base class.
- CPropertySheet::DoModal causes a first chance exception on Windows 95 (the exception can be ignored).
- Property sheets now have a minimum width.
- CToolBar requires a minimum button size.
- Do not replace CFileDialog's default hook procedure.
- Altering CFileDialog's standard Explorer interface requires a call to GetParent.
- CFileDialog member functions GetFileName and GetFileTitle are functionally reversed.
- MFC threads cannot be created during DLL startup.
- Regular DLLs using the MFC shared library require AFX_MANAGE_STATE in exported functions.
- MFCANS32.DLL no longer exists: OLE functions in MFC applications now require Unicode arguments.
Knowledge Base articles referenced in this article are available in the MSDN Library. You can also search the KB from http://support.microsoft.com.
Before MFC version 4.0, MFC preregistered four window classes, as documented in MFC Technical Note 1. These WNDCLASSes were AfxWnd, AfxFrameOrView, AfxMDIFrame, and AfxControlBar.
Most code that prevented more than one instance of an application relied on these classes, but, as of version 4.0, the classes are not registered until a window of that type is created.
Custom WNDCLASS-based windows that rely on ::GetClassInfo to retrieve class information from the MFC window classes will likely fail to be displayed and will send the message that Window creation failed and GetLastError returned the value 0x57F (ERROR_WNDCLASS_DOES_NOT_EXIST). The message is sent to the debug output window if MFC tracing is turned on. The error message corresponding to this error is "Cannot find window class".
To prevent this situation, provide all of the necessary information when registering custom window classes with RegisterClass or AfxRegisterClass and do not rely on ::GetClassInfo to retrieve class values for MFC window classes.
For more information, see the Knowledge Base article Q140596 and the Knowledge Base sample Q141752.
The m_templateList member variable of CWinApp was undocumented in MFC 3.x, but was used commonly enough to create porting problems. The recommended way to access the templates for an application is to use the GetFirstDocTemplatePosition and GetNextDocTemplate member functions of CWinApp.
For more information, see the Knowledge Base article Q106455.
The member variable m_pfnConstruct was a documented member of CRuntimeClass in MFC versions prior to 4.0, but the name was changed to m_pfnCreateObject to reflect a change in parameters and return value. The documentation included with Visual C++ 4.0 was not updated to reflect this change and incorrectly references the old member variable name.The documentation for Visual C++ 4.1 and later, however, is up to date.
CStatusBar and CToolBar now wrap the functionality of the Win32 common controls. Any code that relied on or modified the private, undocumented implementation of these classes will likely break when compiled for MFC 4.0. These two common controls support a greater range of common customizations than the previous default MFC implementation and do not require significant overrides of the MFC source for such tasks as constructing palette bars or making resizable toolbars. If needed, the old implementation of these two classes is still available as the COldStatusBar and COldToolBar classes.
Much of the MFC implementation of CPropertySheet has now changed to wrap the Windows Property Sheet common control. There have been formatting and sizing changes. More importantly, if previous code used any of the private MFC implementation of CPropertySheet, it will likely break since most of the undocumented members of that class are no longer there.
CPropertySheet now always changes its font to the default font. Even if the font of the property pages is changed in the resource editor, property pages will be displayed at run-time with the system font. If it is necessary to change the font, call SetFont in OnInitDialog and then do an appropriate MoveWindow to resize the sheet and move and resize all controls on the page. Also, the property sheet is set back to its original size whenever a page is activated, so it is necessary to resize the page in response to a click on the tab control. For more information, see the Knowledge Base article Q142170.
Property sheet modifications should be done in OnInitDialog after a call to the base class. During CPropertySheet::OnInitDialog, the property sheet is resized and the four standard buttons (OK, Cancel, Apply, and Help) are hidden at the bottom of modeless property sheets. The proper place to modify the size of the sheet or to customize the four property sheet buttons is in OnInitDialog after the call to the base class. It was common in previous versions of MFC to hide some of the buttons shown with a modal property sheet in OnCreate. These buttons can now be removed easily by modifying styles in the PROPSHEETHEADER structure CPropertySheet::m_psh. For more information, see the Knowledge Base articles Q140585 and Q141039.
CPropertySheet::DoModal causes a first chance exception on Windows 95 because the property page sets required styles in the dialog resource. The operating system needs to handle this and the message can be ignored. If you surround the DoModal call with a try/catch(...) block in an effort to handle the exception yourself, you will get a stack fault. For more information, see DoModal.
The minimum width of a CPropertySheet window is the size of the four buttons (OK, Cancel, Apply, and Help) that would show up along the bottom of a modal property sheet. This width applies even to modeless property sheets, which do not show the four buttons along the bottom.
Toolbars now require that the width of the button size be at least 7 pixels greater than the image size. The documentation that ships with Visual C++ 4.0 was not updated to reflect this change and is incorrect. The ASSERT that MFC version 4.0 uses to verify correct parameters in SetSizes also incorrectly checks for the old value of 6. There are other limits on the sizes of the toolbar, buttons, and images, but these are correctly covered by ASSERT statements in the MFC source and have not changed since MFC 3.x. For more information, see the Knowledge Base article Q141444.
MFC always specifies its own hook procedure, _AfxCommDlgProc, for the Open File Dialog during the construction of the CFileDialog object so that it can route notifications for the dialog to the proper handlers. As of MFC 4.x, this hook procedure is used to subclass the CFileDialog object to the Open File Dialog window. If the hook procedure is replaced, subclassing will not happen and any attempt to use the CFileDialog (or an embedded control variable on it) as a window will fail.
When you use the Windows Explorer-style CFileDialog (the default on Windows 95), MFC 4.x assumes the Windows Explorer model of customization. This implies that custom improvements to the File dialog are included on a separate template that is added around the standard Windows Explorer dialog.
In MFC 4.x, the actual CFileDialog window is a child dialog of the main File Common Dialog, even if you are not providing a template to customize the dialog. Therefore, if you have a need to alter the standard Windows Explorer interface by moving or hiding controls, prefix all GetDlgItem calls to Windows Explorer controls with GetParent. For example,
GetParent()->GetDlgItem(IDOK) will return a pointer to the Open/Save button on the Windows Explorer dialog. However, this is not recommended because code which relies on the details of the standard Windows Explorer dialog controls will break if the Windows Explorer layout is changed in the future.
MFC 4.0 implementation of CFileDialog member functions GetFileName and GetFileTitle is reversed from previous versions of MFC. For example, in MFC 4.0, given the file "C:\ARTICLE.TXT", CFileDialog::GetFileName returns "ARTICLE.TXT" and CFileDialog::GetFileTitle returns "ARTICLE". Previous versions of MFC returned exactly the opposite. The functions have been changed to work like the Win32 API functions of the same names. However, the documentation included with Visual C++ 4.0 was not updated to reflect these changes. The documentation for Visual C++ 4.1, however, is up to date.
In previous versions of MFC, it was possible to create a thread during the startup of an MFC DLL. This required calling AfxBeginThread or CWinThread::CreateThread in DllMain, in RawDllMain, in
InitInstance in the DLL, or in any functions called by these. Due to synchronization of MFC thread startup code and blocking at DllMain during DLL_PROCESS_ATTACH and DLL_THREAD_ATTACH, this is no longer permitted. MFC 4.0 DLLs that attempt to do this will hang when loaded by an application. For more information, see the Knowledge Base article Q142243.
Previously, the USRDLL model required that MFC be statically linked to the DLL. It is now possible to link dynamically to the MFC40.DLL from a Regular DLL, the new term for _USRDLLs. However, to convert a _USRDLL to a Regular DLL using MFC in a shared library, you need to make sure that you manage your module state information correctly. The single line:
should be added to the beginning of any function exported from the DLL which operates on MFC objects. If the module state is not switched appropriately, it could cause the following problems: dialogs and windows fail at creation in a DLL because of missing resources, functions for the wrong application object get called and cause stack overflow or unpredictable results, unrecognized run-time class information, bad window to MFC object handle map linkage, and more. For more information, see the Knowledge Base article Q140850 and MFC Technical Note 58.
In MFC 3.x, a special DLL was used (MFCANS32.DLL) to automatically convert between Unicode and MBCS when OLE interfaces were called. MFC 4.x does not use this DLL and instead talks directly to the Unicode OLE interfaces. To handle this change, MFC applications now must pass the correct type of parameters — whether Unicode or MBCS — to OLE functions. MFC 4.0 has provided a number of macros that makes this task easier. For more information, see MFC Technical Note 59.