Visual C++/MFC Frequently Asked Questions

Scot Wingo
Stingray Software

Version 5.0, updated 5/15/97

MSDN Editor's Note   This document was copied with permission from the "Microsoft Visual C++/Microsoft Foundation Classes (MFC) Frequently Asked Questions (aka the MFC FAQ)," written and compiled by Scot Wingo and sponsored by Stingray Software. You can find out more about Stingray Software's products at http://www.stingsoft.com/.

The latest version of the MFC FAQ can be found on the World Wide Web at http://www.stingsoft.com/mfc_faq/. If you have any questions or comments concerning the MFC FAQ, please address them to mfc_faq@stingsoft.com.

This FAQ is not produced or checked for technical accuracy by Microsoft Corporation.

About Stingray Software

The MFC FAQ is graciously sponsored by Stingray Software. Stingray Software was founded in July 1995 with the goal of creating best-of-breed object oriented developer tools for Windows programmers. Since its inception, Stingray has focused on filling the holes not covered by the MFC. Recently, Stingray has also ventured into the Java developers tool market by offering its popular object-oriented tools in the form of Java class libraries that are compatible with the Microsoft’s Visual J++ and Symantec’s Café product lines.

Copyright Notice

This document is compilation copyright © 1997 by Scot Wingo. It may be freely copied and/or distributed in its entirety as long as this copyright notice is not removed. It may not be sold for profit or incorporated into commercial products without the author's written permission. Compilation copyright means that you can freely use individual sections of this document, but any significant collection of sections is subject to the copyright. Hey, I may want to turn this into a book or a movie some day!

This FAQ is in no way connected with Microsoft. It contains some answers to frequently asked questions about their products. The author in no way guarantees that any of these answers are correct. This is just a collection of information posted to public online forums to help the average MFC programmer.

The maintainer of this FAQ can be contacted at mfc_faq@stingsoft.com.

Contents

Generic Class Questions
GDI Class Questions
Windows, Controls, and Dialogs Class Questions
Views, Documents, and Frame Class Questions
OLE Class Questions
WOSA Class Questions
DLL and Build Questions
MFC Tips, Tricks, and Caveats
Wizard Questions
Visual C++ Questions

Generic Class Questions

CException—Exceptions and Exception Handling

CException—Exceptions and Exception Handling

How do I throw a CUserException-derived exception?

When I try to catch a derived exception I get the following error: "error C2039: 'classCMyException': is not a member of 'CMyException' 'classCMyException': undeclared identifier 'IsKindOf': cannot convert parameter 1 from 'int*' to 'const     struct CRuntimeClass*"

You need to make your CMyException class dynamically creatable by using the DECLARE_DYNAMIC() and IMPLEMENT_DYNAMIC() macros. The CATCH macro expects to be able to access run-time information about the thrown class.

Mike Blaszczak, blaszczak@bix.com comp.os.ms-windows.programmer.misc, 6/5/95

Do my exceptions have to be derived from CUserException?

No. The "User" in CUserException simply means that the exception is caused by user actions. It is a common misconception that this is the only exception you can derive from.

nuj@kruger.dk via email, 11/23/95

GDI Class Questions

CDC
CBitmap

CDC

How do I create a CDC from an HDC?

Sometimes the Windows API will just give you a handle to a DC and you might want to create a CDC from that. One example is owner-drawn lists, combos, and buttons. You will receive a draw item message with an hDC. Here's some code to turn that hDC into the more familiar CDC.

You can use this technique for any of the other MFC class/Windows handle pairs, too.

void MyODList::DrawItem(LPDRAWITEMSTRUCT lpDrawItem)
{
    CDC myDC;
    myDC.Attach(lpDrawItem->hDC);
    // Do more stuff here.
    // If you don't detach, it will get deleted and Windows will
    // not be happy if you delete its dc.
    myDC.Detach();
}

Another approach is to call the CDC FromHandle method:

    CDC * pDC = CDC:FromHandle(lpDrawItem->hDC);

It's not clear which is "better"—FromHandle() is less error-prone because you do not have to remember to "detach".

Jim McCabe, jmccabe@portage1.portup.com, 6/5/95

CBitmap

How do I read a 256-color bitmap file from disk?

Currently, MFC does not contain direct support for reading and displaying DIBs or BMPs. However, there are a number of sample applications that illustrate just how to do this.

The first sample is the MFC sample application DIBLOOK. The MULTDOCS sample uses the same source code provided by DIBLOOK to read and display DIBs and BMPs.

Two other examples provided with Visual C++ are the SDK samples DIBVIEW and SHOWDIB.

Question posted on comp.lang.c++, 6/5/95, found this in MS FAQ, 6/25/95

Windows, Controls, and Dialogs Class Questions

Windows
Controls
Dialogs
Control Bars, Status Bars, Toolbars, Dialog Bars
Menus
Windows Common Controls (aka Windows 95 Controls)
CSplitterWnd FAQs

Windows

How can I use a custom icon for a window?

The Microsoft Foundation Class Library stores icons for the main frame window and the MDI frame window as resources. The icon with resource ID AFX_IDI_STD_MDIFRAME is the icon for the MDI frame window, and the icon with resource ID AFX_IDI_STD_FRAME is the icon for the main frame window. To replace these icons in your application, add an icon to your resources file with the appropriate ID.

The application specifies the icon for a view in an MDI child window when it creates the template. The application uses the icon with the specified resource ID when the user minimizes the MDI child window that contains the corresponding view.

This technique allows you to specify one icon for the application to associate with these windows. Windows also supports dynamically painting a minimized window. To do this with MFC, use AfxRegisterWndClass() to register a window class with a NULL icon handle. Override the PreCreateWindow() function in the window class for the dynamically painted icon and copy the name returned by AfxRegisterWndClass() into the lpszClassName member of the CREATESTRUCT. This creates the window using the class that has a NULL icon. When the user minimizes this window, the icon receives WM_PAINT messages that it can process to display information appropriately. To do so, override the OnPaint() message handler and call the IsIconic() function to see if the window is minimized. If so, create a CPaintDC object and use it to draw on the icon. If the window is not minimized, call the base class version of OnPaint() to update the window normally.

Visual C++ Knowledge Base article Q109039, 6/4/94

How do I change the styles for a window that's created by MFC?

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. For more information, see Visual C++ Knowledge Base article Q99847.

Visual C++ Knowledge Base article Q109039, 6/7/95

How do I get the minimal size of a window using MFC?

Write a handler for WM_GETMINMAXINFO.

Mike Blaszczak, blaszczak@BIX.com, via programmer.misc, 6/12/95

How do I change a Window's title?

AfxGetApp()->m_pMainWnd->SetWindowText("My Window Title");

—Or—

AfxGetMainWnd()->SetWindowText ( "My Own Title" );

aj536@freenet.toronto.on.ca, mfc-l, 7/9/95

How do I get rid of "Untitled" in my main window caption?

Override the PreCreateWindow() function in your MainFrame class and do the following in it:

cs.style &= ~FWS_ADDTOTITLE; 

You can also set the initial window position (cs.x, cs.y, cs.cx, cs.cy) this way and change your class (cs.lpszClass) this way! Remember to call CFrameWnd::PreCreateWindow at the end...

netninja@svpal.org, programmer.misc, 7/29/95

How do I maximize my MDI child?

void CMainFrame::ActivateFrame(int nCmdShow)
{
    if (!m_bActivated) 
    {
        m_bActivated = TRUE;
        nCmdShow = SW_SHOWMAXIMIZED;
    }
    CFrameWnd::ActivateFrame(nCmdShow);
}

where m_bActivated is a member variable of your frame object.

duane@anasazi.com, programmer.win32, 8/3/95

Why does focus go nutso with a CSplitterWnd?

Whenever I move the splitter bar, the I-beam cursor in my edit control goes away. I have to click again in the edit control to get back the cursor.

The Knowledge Base Article Q108434, "FIX: CSplitterWnd Class Does Not Handle All Focus Cases," explains the focus problem associated with splitter windows and a couple of workarounds to the problem. This may be of help to you.

Ramesh (NetQuest), MSMFC, 8/3/95

How do I make my first MDI child window start out maximized?

Here is a solution that works for me:

class CChildFrame : public CMDIChildWnd
{
   // .. stuff deleted ...
   // This makes the MDI child maximized.
     virtual void ActivateFrame(int nCmdShow) { 
            // if another window is open, use default
       if(GetMDIFrame()->MDIGetActive())
      CMDIChildWnd::ActivateFrame(nCmdShow); 
       else
      CMDIChildWnd::ActivateFrame(SW_SHOWMAXIMIZED); // else open maximized.
  }
// ... stuff deleted ...
};

Stephen Bade, bade@convergent-design.com

Controls

How do I get a CControl from a Dialog Template?

You can get a pointer to a control from an already created dialog control by doing a simple typecast of the results from GetDlgItem. Here's an example that creates a CButton from a checkbox with ID  :  IDC_CHECK1.

void my_function(CDialog * pDialog)
{
    CButton * pButton = (CButton *)pDialog->GetDlgItem(IDC_CHECK1);
    ASSERT(pButton != NULL);
    pButton->SetCheck(m_bShowState);
}

Note that it's always safer to check for the validity of the results from GetDlgItem.

Scot Wingo, scot@stingsoft.com

How do I subclass a control using MFC?

Read the documentation on SubClassDlgItem. Here's an example of how to call it:

BOOL CMyDialog::OnInitDialog()
{
    // Do your subclassing first.
    m_MyControl.SubClassDlgItem(ID_MYCONTROL, this);
    // Let the base class do its thing.
    CDialog::OnInitDialog();
    // Perhaps do some more stuff.
    // Be sure to call Ctl3d last, or it will cause
    // assertions from multiple subclassing.
    Ctl3dSubclassDlg(m_hWnd, CTL3D_ALL);
}

Mike Williams, mikew@marlin.ssnet.com, mfc-l, 6/1/95

Why do I get an ASSERT when I subclass a control?

Make sure that you subclass the control before you call Ctl3dSubclassDlg. If the 3-D control DLL is loaded first, it will already have subclassed your controls and you will get an assert.

Mike Williams, mikew@marlin.ssnet.com, mfc-l, 6/1/95

How do I validate the contents of a control when it loses focus?

Note   This is in the Microsoft Software Library (MSL).

The FCSVAL sample application was created to show how an application can do control-by-control validation in a dialog box.

The application itself is just a modal dialog box displayed by the CWinApp::InitInstance(). After displaying the dialog box, InitInstance() simply quits the application.

The important part of the sample takes place in the dialog-box class implementation: There are two edit controls. The first takes input of an integer between 1 and 20. The second takes a character string as input with length less than or equal to 5. When you tab or click from control to control within the displayed dialog box, the contents of the control that is losing focus are validated.

The CFocusDlg Class

The application's functionality centers on the CFocusDlg class and its implementation of four message handlers (discussed below). Normal data exchange (DDX) and validation (DDV) using the routines provided by MFC take place in OnInitialUpdate(), when the dialog box is first displayed, and when the user chooses the OK button to accept the input. This is default behavior provided by ClassWizard when member variables are connected to dialog-box controls and can be examined in the dialog class DoDataExchange() function.

Validating control contents when switching focus from one control to the next is done by handling the EN_KILLFOCUS notification sent by the edit control that is losing focus. The idea here is to check the contents and, if they are not valid, to display the message box, inform the user, and then set the focus back to the control from which it came. Unfortunately, some difficulties arise when trying to set the focus (or display the message boxes) within a killfocus message handler. At this point, Windows is in an indeterminate state as it is moving focus from one control to the other. This is a bad place to do the validation and SetFocus() call.

The solution here is to post a user-defined message to the dialog box (parent) and do the validation and SetFocus() there, thus waiting for a safer time to do the work. (See "CFocusDlg::OnEditLostFocus()" in the file FOCUSDLG.CPP and "WM_EDITLOSTFOCUS user-defined message" in the file FOCUSDLG.H.)

Another thing you will notice about this function is that it uses TRY/CATCH to do the validation. The provided DDX/DDV routines throw CUserExceptions when failing to validate or load a control's data. You should catch these and do the SetFocus() in the CATCH block.

Note   This sample has other cool stuff, but this is the major one I've seen asked about on the Net.

Knowledge Base article Q142481, 6/25/95

How do I enable/disable a bank of checkboxes?

I don't know about a magic way to do this using a single HWND, but there is a simple and self-documenting technique that I've been using for a long time. You can make a routine that accepts an array of UINTs (your control IDs) and a visibility flag.

This function can be a standalone function, or you can put it inside a class. I have been collecting little utility functions like this and keep them in a CDialogBase class—when I create a new dialog box in ClassWizard, I fix up the code to derive from CDialogBase instead of CDialog.

For example, the function might look like this:

void CDialogBase::ShowControls(UINT* pControls, UINT cControls, BOOL fVisible)
{
    for (UINT uIndex = 0; uIndex < cControls; uIndex++)
    {
        CWnd* pwnd = GetDlgItem(pControls[uIndex]);
        if (pwnd)
        {
            pwnd->ShowWindow(fVisible ? SW_SHOW : SW_HIDE);
            pwnd->EnableWindow(fVisible);
        }
    }
}

Then later, often in your OnInitDialog handler, you can call this function with your control group:

#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0]))
{
    static UINT aGroup1[] = { DLG_CHBOX1, DLG_CHBOX2, 
            DLG_STATIC1 };
    static UINT aGroup2[] = { DLG_LABEL2, DLG_LABEL7 };
    ShowControls(aGroup1, SIZEOF_ARRAY(aGroup1), TRUE);
    ShowControls(aGroup2, SIZEOF_ARRAY(aGroup2), FALSE);
}

You can find many uses for these control arrays later, too. (Changing fonts in a series of controls, etc.) Good luck.

jmccabe@portage1.portup.com, mfc-l, 7/18/95

How do I change the background color of a control?

Your dialog can trap the WM_CTLCOLOR message—look up the MFC Help file notes for CWnd::OnCtlColor(). Before a control is about to paint itself, the parent window receives a chance to set its own default text color and background brush.

jmccabe@portage1.portup.com, mfc-l, 7/18/95

Also, check out the Knowledge Base article Q117778, "Changing the Background Color of an MFC Edit Control."

Ramesh, MSMFC, 7/19/95

How do I trap the key for my control?

Handle WM_GETDLGCODE and return the appropriate value. Remember that the list box (or any other control) can handle keyboard input only when it has the focus.

Joe Janakovic, joej@golddisk.com, programmer.misc, 8/21/95

How can I DDX with a multiple selection list box?

Download MLBDDX.ZIP from the MSMFC library on CIS. You'll get all the necessary code. When the dialog closes, a provided CStringList will be filled with the selected items. Freeware.

Patrick Philippot, CIS email, 8/3/95

How do I change the background color of a button?

Note: the method in "How do I change the background color of a control?" will not work for buttons!

If you want to change the color of a dialog button, you have to use an owner-draw button. (You can use bitmap buttons.) Changing the color through OnCtlColor() will not work for buttons. The following Knowledge Base articles may be of help to you: Q32685, "Using the WM_CTLCOLOR Message," and Q64328, "SAMPLE: Owner-Draw: 3-D Push Button Made from Bitmaps with Text." This article explains sample code for a owner-draw button.

Ramesh (NetQuest), MSMFC, 8/3/95

Why isn't CEdit putting things on separate lines?

Make sure that the lines are separated with \r\n, not just \n.

sutor@watson.ibm.com, mfc-l, 8/7/95

How do I get to the CEdit in a combo box?

CComboCox combo;
CEdit edit;
// Combobox creation ...
// ...
POINT tmpPoint = {1,1};
edit.SubclassWindow( combo.ChildWindowFromPoint(tmpPoint)
->GetSafeHwnd());

jahans@slb.com, mfc-l, 8/25/95

Or:

Look into the MFC sample—npp - npview.cpp! Turns out all combos create their edits with an ID of 1001 (decimal), so—if pComboBox is the pWnd object pointing to the combo—all you need is:

pComboBox->GetDlgItem(1001);

How do I load more than 64K into an edit control?

The Rich Edit Control available in Visual C++ 2.1 and later supports much more than 64K. The WordPad sample is a great way to learn more about this subject. If you're stuck with 16-bit programming, I think that Magma Systems has a 16-bit DLL that does this. Contact Marc Adler at 75300.2062@compuserve.com for details.

Scot Wingo—scot@stingsoft.com

How do I subclass the list box portion of a combo box?

The listbox portion of a combo box is of type COMBOLBOX (notice the "L").    Because the ComboLBox window is not a child of the ComboBox window, it is not obvious how to subclass the COMBOLBOX control. Luckily, under the Win32 API, Windows sends a message to the COMBOBOX (notice no "L") called WM_CTLCOLORLISTBOX before the list box is drawn. The lParam passed with this message contains the handle of the list box. For example:

LRESULT CFileUpdateCombo::OnCtlColorListBox(WPARAM wParam, 
   LPARAM lParam) 
{
    if ( ! m_bSubclassedListBox ) 
{
        HWND hWnd = (HWND)lParam;
        CWnd* pWnd = FromHandle(hWnd);
        if ( pWnd && pWnd != this )
        {
            // m_ListBox is derived from CListBox.
            m_ListBox.SubclassWindow(hWnd );
            m_ListBox.SetOwner(this); 
            m_bSubclassedListBox = TRUE;
        }
    }
    return (LRESULT)GetStockObject(WHITE_BRUSH);
}

mikem@abelcomputers.com, email, 9/7/95

How do I inherit from an MFC standard control class and provide initialization code that works on both subclassed and nonsubclassed controls?

Editor's note (Scot Wingo):   OK, this probably isn't a FAQ, but I thought it sounded pretty cool.

I have a fix, but you may not like it; however, it takes care of both subclassing methods.

If SubclassWindow() was virtual, all problems would be solved, as SubclassDlgItem calls SubclassWindow(), and common initialization could be called from this point and from OnCreate(). Even better would be a virtual SetupWindow() function called from all initialization points by Microsoft's code.

C'est la vie. My fix might slow the message loop for the control in question, but so far I haven't seen any performance hits. Override the virtual function WindowProc() for your control something like the following (call SetupWindow() in OnCreate() also):

LRESULT CExtendControl::WindowProc( UINT message, WPARAM wParam,
   LPARAM lParam)
{
    if (!m_bSetup)
        SetupWindow();
    return CEdit::WindowProc(message, wParam, lParam );
}
// This is a virtual function. Use it for Hwnd setup in all inherited 
// classes. It will work for a subclassed window.
void CExtendControl::SetupWindow()
{
    ASSERT( m_hWnd );
    m_bSetup = TRUE;
    *** Insert Initialization Code here!***
}

Jody Power, jodyp@andyne.on.ca)

Dialogs

How do I center my dialog?

Use the CWnd::CenterWindow method to accomplish this. I usually put it in my OnInitDialog overloaded function. Since CDialog is an ancestor of CWnd, you can call the method directly:

 BOOL CMyDialog::OnInitDialog()
{
    // Perform any other dialog initialization up here.
    CenterWindow();
    return TRUE;
}

Scot Wingo, scot@stingsoft.com, 6/1/95

How do I get the "old style" common dialogs on Windows 95?

MFC detects if it is running on Windows 95, and if so, replaces the standard FileOpen dialog box with an Explorer version of the File Open dialog box. You can prevent MFC from using this Explorer version by adding the following line to your CFileDialog derived class constructor:

m_ofn.Flags &= ~OFN_EXPLORER;

andyd@andyne.on.ca (Andy DeWolfe), via programmer.win32, 5/10/95

How do I subclass a Windows 95 common dialog?

You can do it, but Microsoft has made it much more difficult in Windows 95. You need to create a "child dialog template" (with the WS_CHILD style) and set it to m_ofn.lpTemplateName (making sure m_ofn.hInstance is set to your app instance). This template must contain only the controls that you are adding to the dialog (that is, not the whole dialog with the standard controls duplicated, as in Windows 3.x).

When the dialog is invoked, your template will appear (by default) below the regular file dialog controls. If you put a static control with id stc32 (defined in include\dlgs.h), the common dialog code will rearrange things so that the original controls will appear wherever you put the stc32 control. (You don't have to size it to match—the common dlg code will do that for you.)

You will need to supply m_ofn.lpfnHook and handle your additional controls through the hook proc. Note that since the system puts your dialog template on top of the normal dialog, MFC message routing won't get to your controls, so you can't code them through a message map in your CFileDialog derivative. If anybody has found a way around this, I'd love to hear it!!

This is very messy and Microsoft knows it. They promise a fix in MFC 4.0.

Editor's note (Scott Wingo)   This is much nicer in 4.0. There are virtuals to override for getting callbacks, plus it even handles the old and new style templates—pretty clever stuff!

joej@golddisk.com, via programmer.win32, 6/10/95

CDialog::Create() fails. What could be wrong?

Invalid HWND passed as a parent.

Invalid dialog resource ID passed. (Be careful about numeric IDs vs. string IDs—be careful with #define ID_MYDIALOG 0x1234—it is a "string" ID to the resource compiler.)

One or more controls on your dialog could not be created, usually because of the use of a custom control that was not registered. Calling EndDialog during the OnInitDialog message (or some other handler called early in the game)!

NULL HWND passed as parent when dialog has WS_CHILD style.

That's about all I can think of right now.

Dean McCrory, MSMFC, 6/16/95

How do I create a toolbar/status bar in a dialog?

There's a sample in the Microsoft Software Library, DLGCBR, that demonstrates how to do this. Basically there's four steps, outlined and then coded below.

To add a control bar to a dialog, you must create the control bar as usual and then make room for the control bar within the client area of the dialog. For the control bar to function properly, the dialog must duplicate some of the functionality of frame windows. If you want ON_UPDATE_COMMAND_UI handlers to work for the control bars, you also need to derive new control bar classes, and handle the WM_IDLEUPDATECMDUI message. If your dialog is not the main window of your application, you will also need to modify its parent frame window to pass the WM_IDLEUPDATECMDUI message on to the dialog's control bars.

To make room for a control bar within the client area of the dialog, follow these steps in your dialog's OnInitDialog() function:

  1. Create the control bars:
    CRect rcClientStart;
    CRect rcClientNow;
    GetClientRect(rcClientStart);
    RepositionBars(AFX_IDW_CONTROLBAR_FIRST,
    AFX_IDW_CONTROLBAR_LAST,
    ,reposQuery,
    rcClientNow);
    
  2. Figure out how much room the control bars will take by using the reposQuery option of RepositionBars():
    CPoint ptOffset(rcClientStart.left - rcClientNow.left,
    rcClientStart.top - rcClientNow.top);
    ptOffset.y += ::GetSystemMetrics(SM_CYMENU);
    CRect rcChild;
    CWnd* pwndChild = GetWindow(GW_CHILD);
    while (pwndChild)
    {
    pwndChild->GetWindowRect(rcChild);
    rcChild.OffsetRect(ptOffset);
    pwndChild->MoveWindow(rcChild, FALSE);
    pwndChild = pwndChild->GetNextWindow();
    }
    
  3. Move all the controls in your dialog to account for space used by control bars at the top or left of the client area. If your dialog contains a menu, you also need to account for the space used by the menu.

  4. Increase the dialog window dimensions by the amount of space used by the control bars:
    CRect rcWindow;
    GetWindowRect(rcWindow);
    rcWindow.right += rcClientStart.Width() - rcClientNow.Width();
    rcWindow.bottom += rcClientStart.Height() - rcClientNow.Height();
    MoveWindow(rcWindow, FALSE);
    
  5. Position the control bars using RepositionBars().

To update the first pane of a status bar with menu item text, you must handle WM_MENUSELECT, WM_ENTERIDLE, and WM_SETMESSAGESTRING in your dialog class. You need to duplicate the functionality of the CFrameWnd handlers for these messages. See the CModelessMain class in the sample program for examples of these message handlers.

To allow ON_UPDATE_COMMAND_UI handlers to work for other status bar panes and for toolbar buttons, you must derive new control bar classes and implement a message handler for WM_IDLEUPDATECMDUI. This is necessary because the default control bar implementations of OnUpdateCmdUI() assume the parent window is a frame window. However, it doesn't do anything but pass the parent window pointer on to a function that only requires a CCmdTarget pointer. Therefore, you can temporarily tell OnUpdateCmdUI() that the parent window pointer you are giving it is a CFrameWnd pointer to meet the compiler requirements. Here's an example:

LRESULT CDlgToolBar::OnIdleUpdateCmdUI(WPARAM wParam,LPARAM lParam)
{
    if (IsWindowVisible())
    {
        CFrameWnd* pParent = (CFrameWnd*)GetParent();
        if (pParent)
            OnUpdateCmdUI(pParent, (BOOL)wParam);
    }
    return 0L;
}

To pass WM_IDLEUPDATECMDUI messages on to dialogs other than the main window, save dialog pointers in your frame window class and create a WM_IDLEUPDATECMDUI handler in that class. The handler should send the WM_IDLEUPDATECMDUI message on to the dialog child windows by using CWnd::SendMessageToDescendants(). Then perform default processing for the message within the frame window.

Visual C ++ Knowledge Base article Q123158, 6/25/95

Why isn't my CDialog::PreCreateWindow() getting called?

PreCreateWindow does not get called when you create a dialog box. If you would like to init some data/controls for a dialog box, you have to trap the OnInitDialog message and then do your stuff there. PreCreateWindow is used to modify params for a window that you are creating.

ewalker@tezcat.com, mfc-l, 7/12/95

How do I embed a common dialog in a property page?

This question comes up frequently on the MFC forum of CompuServe and the simple answer—unfortunately—is that there is no way to do it :-(

chris@chrism.demon.co.uk, programmer.win32, 7/12/95

[Correct. The problem is that the Windows implementation of these dialogs is a modal dialog. In order to embed something on a property sheet, it would need to be implemented as a modeless child dialog window. Because the Windows API does not expose modeless child capability for any of the common dialogs, you cannot embed them on a property sheet. The only way to get the functionality you are after is to "roll your own" implementation of these pages.

Dean McCrory's reply to MSDN editor's query, 4/25/96]

Why can't I DDX/DDV to initialize my CDialog controls?

You can't do anything with the dialog controls until your dialog is created—which doesn't happen until DoModal(). The standard way of overcoming the problems is to create member variables for the data, initialize them before calling DoModal, and then transfer the values in OnInitDialog. Or perhaps in UpdateData(). Much like the ClassWizard member variables do it.

So have your dialog include a CStringList or CStringArray, put the values for the listbox in that and transfer them to the listbox in OnInitDialog. [Etc....]

Niels Ull Jacobsen, null@diku.dk, programmer.controls, 7/11/95

Init your dialog in OnInitDialog. If necessary, pass a pointer to your document to the constructor of your dialog (and save it in a private/protected m_pDoc member).

jhasling@gascad.co.at, programmer.controls, 7/11/95

How do I change the captions of a CPropertyPage?

You can change the label before adding the page to the property sheet in the following way. You have to derive a class from CPropertyPage and add a public function, SetCaption, which sets the caption.

void CPage1::SetCaption(char *str)
{
    m_strCaption = str; // m_strCaption is protected member of
                        // CPropertyPage
}

Now you can use the SetCaption() function in the following way:

CMySheet my("My PropSheet");
CPage1 p1;
p1.SetCaption(str); // Setting the caption.
my.AddPage(&p1);
CAnotherSheet newps("New Sheet");
CPage1 p2;
p2.SetCaption(newstr);
newps.AddPage(&p2);
my.DoModal();

Ramesh (NetQuest), MSMFC, 8/3/95

How do I trap F1 in my dialog?

The Knowledge Base article Q117563, "How to Trap WM_KEYDOWN Messages in a CDialog," explains a way to trap the WM_KEYDOWN messages in the dialog box.

"SAMPLE: Context Sensitive Help in a CDialog" explains how to provide context-sensitive help in a dialog. It also points to sample code (Knowledge Base article Q110506).

Ramesh (NetQuest), MSMFC, 8/31/95

How do I change the icon for a dialog-only MFC application?

Add the following code to the InitInstance() for the CWinApp derived class:

BOOL CDialogTestApp::InitInstance()
{
    // ...
#if(_MFC_VER >= 0x0300)
    SetClassLong(m_pMainWnd->m_hWnd,GCL_HICON,
        (LONG)LoadIcon(IDC_ICONDIALOGAPP));
#else
    SetClassWord(m_pMainWnd->m_hWnd,GCW_HICON,
        (WORD)LoadIcon(IDC_ICONDIALOGAPP));
#endif
    // ...
    m_pMainWnd->ShowWindow(m_nCmdShow);
    return TRUE;
}

Control Bars, Status Bars, Toolbars, Dialog Bars

How do I add a combo box to my toolbar?

You can do this using the CToolBar::SetButtonInfo() method. The MFC sample CTRLBARS shows how to do this in file mainfrm.cpp. Basically, you call SetButtonInfo to create a blank space (TBBS_SEPARATOR) for the combo box, with the resource ID of the help and tool tip for the combo box. You then use GetItemRect to get the bounding rectangle of the combo box, and create a combo box window of your own in that space.

Scot Wingo, scot@stingsoft.com, 6/1/95; martynl@cix.compulink.co.uk—updated

How do I update the text of a pane in a status bar?

By default, a CStatusBar pane is not enabled when the pane is created. To activate a pane, you must call the ON_UPDATE_COMMAND_UI() macro for each pane on the status bar and update the panes. Because panes do not send WM_COMMAND messages, you cannot use ClassWizard to activate panes; you must type the code manually. For example, suppose one pane has ID_INDICATOR_PAGE as its identifier and that it contains the current page number in a document. To make the ID_INDICATOR_PAGE pane display text, add the following to a header file (probably the MAINFRM.H file):

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.

Visual C++ Knowledge Base article 109039, 6/4/94

How do I make my CToolBar customizable at run time?

You might consider reading article "CToolBarCtrl: Handling Customization Notifications" in the Product Documentation of Visual C++ 2.1.

Here is the relevant extract :

"A Windows toolbar common control has built-in customization features, including a system-defined customization dialog box, which allow the user to insert, delete, or rearrange toolbar buttons. The application determines whether the customization features are available and controls the extent to which the user can customize the toolbar. These customization features are available in the CToolBarCtrl class but not in the current CToolBar class.

"You can make these customization features available to the user by giving the toolbar the CCS_ADJUSTABLE style. The customization features allow the user to drag a button to a new position or to remove a button by dragging it off the toolbar. In addition, the user can double-click the toolbar to display the Customize Toolbar dialog box, which allows the user to add, delete, and rearrange toolbar buttons. The application can display the dialog box by using the Customize member function."

R. Rajendran (NetQuest), 76041.2245@compuserve.com, MSMFC Forum, 5/9/95

If you want to make a standard MFC CToolbar customizable, you can download CUSBAR.ZIP from the MSMFC library on CompuServe. This package implements CCustomToolbar, the run-time customizable toolbar, and also provides the necessary user tools (customization dialog box, including the code for a bitmapped listbox). Freeware.

Patrick Philippot, 8/3/95 via email on CSERVE

How do I turn off the toolbar or status bar?

You can turn the status bar off in any of your views (for example in the OnViewStatusBar() method you describe above) with the following code:

if( ((CMainFrame*)GetParent())->m_wndToolBar.IsWindowVisible() )
{
    GetParent()->SendMessage(WM_COMMAND, ID_VIEW_TOOLBAR, 0L);
}
if( ((CMainFrame*)GetParent())->m_wndStatusBar.IsWindowVisible() )
{
    GetParent()->SendMessage(WM_COMMAND, ID_VIEW_STATUS_BAR, 0L);
}

Use 1L instead of 0L for the SendMessage's lParam to turn the bars on.

JKBenjamin@aol.com, via mfc-l, 5/16/95

How do I create a toolbar/statusbar in a dialog?

See section 6.3.5. of this FAQ

Why doesn't MFC support the new controls provided by IE?

Why doesn't MFC have toolbars like the Office 97 applications?

Why doesn't MFC support command bar menus like the Visual C++ IDE?

The new user interface style provided by Microsoft Internet Explorer is implemented by a version of COMCTL32.DLL that's still in beta. The beta import library, DLL, and documentation is available in the Microsoft ActiveX SDK (for Internet Explorer 3.01). The Microsoft ActiveX SDK documentation can be found on the MSDN Library under the SDK Documentation bin. The actual SDK is available for download from http://www.microsoft.com/msdn/. Because the controls are still in beta, MFC doesn't support them. When they're available in their final version, you can assume that a version of MFC that supports them will be forthcoming.

The IDE and the Office applications do not use the COMCTL32.DLL implementations of those controls, and therefore aren't concerned with the release state of the system implementation library.

mikeblas@microsoft.com

Note: The Internet Explorer control is called Rebar. (There was a very good MSJ article about it.) It is useful only if you want to implement Internet Explorer 3 or 4 style toolbars. The toolbars in Visual C++ 5.x and Microsoft Office 97 are different—they are called Command bars. They are not rebar controls—the differences?

Rebar controls "slides" around.

Rebar controls aren't customizable (to my knowledge).

Command bars have cool floating menus. (Rebar controls may do this eventually)

Command bars are less clunky.

Command bars don't have a transparent background.

Command bars are implemented inside of Office97/Developer Studio—they are not available for developers to use. Rebar will be available as part of a common control DLL.

Both have a "cool" or "flat" look and appear three-dimensional when the mouse pointer moves over them.

I don't think Rebar controls are vertically dockable.

If you want to play with Rebar, you need the files COMMCTRL.H and COMCTL32.LIB that come with the ActiveX SDK.

Also, for more information, take a look at the REBAR sample available with the article "Rebar: It Isn't Just for Concrete Anymore" at: http://www.microsoft.com/win32dev/ui/.

FYI   Stingray Software has implemented Office97/Developer Studio style command bars in Objective Toolkit—check out the demo at http://www.stingsoft.com/. Right now Stingray only has the toolbar working, but they promise, a future release, complete menus too!

Menus

How do I get a pointer to the menu bar in an MDI app?

Question: I'm writing an MDI application and I have problems to get a pointer to the actual menu bar. The normal construction doesn't seem to work in MDI:

CMenu *menu;menu = GetMenu()->GetSubMenu(0);

How can I get a pointer to the menu bar to update the menu?

Answer:

AfxGetApp()->m_pMainWnd->GetMenu()->GetSubMenu(n);

mlinar@pollux.usc.edu (Mitch Mlinar), 6/8/95

How do I implement a right-mouse pop-up menu?

///////////////////////////////////////////////////////////////////
// WM_RBUTTONDOWN handler.
//
// Trap this message and display the Button Properties pop-up menu.
// The main frame receives the pop-up menu messages. This allows the
// status bar to be updated with the help text.
///////////////////////////////////////////////////////////////////

void CAppButton::OnRButtonDown(UINT flags, CPoint point)
{
    CMenu menu;
    CMenu *submenu;
    // Load the menu.
    menu.LoadMenu(IDR_LAUNCH);
    // Get the pop-up menu.
    submenu = menu.GetSubMenu(0);
    // Convert to screen coordinates.
    ClientToScreen(&point);
    // Post the menu.
    submenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,
            point.x,    point.y,
            AfxGetApp()->m_pMainWnd,NULL);
}

johnm@unipalm.co.uk, programmer.win32, 7/12/95

It's better to use RBUTTONUP instead; however, right-clicking on dialog controls doesn't generate RBUTTONUP and RBUTTONDOWN messages.

If it's necessary to treat this situation too, a program has to catch the WM_PARENTNOTIFY message in Windows 3.x and Windows NT, and WM_CONTEXTMENU in Windows 95. Here's a code:

// May be dialog too:
BEGIN_MESSAGE_MAP(CMyPropertyPage, CPropertyPage)
    // {{AFX_MSG_MAP(CMyPropertyPage)
    ON_WM_RBUTTONUP()
    ON_WM_PARENTNOTIFY()
    ON_MESSAGE(WM_CONTEXTMENU, OnContextMenu)
    // }}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyPropertyPage::OnRButtonUp(UINT nFlags, CPoint point)=20
{
    PopupMenu (&point);
}
void CMyPropertyPage::OnParentNotify(UINT message, LPARAM lParam)
{
    if (message !=3D WM_RBUTTONDOWN)
        CPropertyPage::OnParentNotify(message, lParam);
    else
    {
        CPoint pt(LOWORD(lParam),HIWORD(lParam));
        PopupMenu (&pt);
    }
}
LONG CMyPropertyPage::OnContextMenu (UINT wParam, LONG lParam)
{
    CPoint pt(LOWORD(lParam),HIWORD(lParam));
    ScreenToClient (&pt);
    PopupMenu (&pt);
    return 0;
}
// *****************************************************************
void CMyPropertyPage::PopupMenu(CPoint* pt)
{
    ASSERT(m_idContextMenu !=3D 0);
    ASSERT(nSubMenu >=3D 0);
    ClientToScreen (pt);
    CMenu FloatingMenu;
    VERIFY(FloatingMenu.LoadMenu(ID_POPUP_MENU));
    CMenu* pPopupMenu =3D FloatingMenu.GetSubMenu (0);
    ASSERT(pPopupMenu !=3D NULL);
    pPopupMenu->TrackPopupMenu (TPM_LEFTALIGN | TPM_RIGHTBUTTON,=20
                                pt->x, pt->y, this);
}

PaulACost@msn.com, via email, 10/15/95

How do I dynamically change the mainframe menu?

CMenu newMenu;
newMenu.LoadMenu (IDR_MENU1);
AfxGetMainWnd()->SetMenu( &newMenu );
AfxGetMainWnd()->DrawMenuBar();
newMenu.Detach ();

Arun Rao, MSMFC, 6/27/95

How do I "attach" a menu to a window's creation/destruction?

Editor's note (Scot Wingo)   the original question talked about dialogs, but you can interpolate this code to any kind of window that you want to have change the menu.

One of the ways to do this is as follows.

Declare a variable CMenu pNewMenu in one of the dialog classes.

Handle the WM_INITDIALOG and WM_CLOSE messages in the dialog class as follows:

BOOL CMydlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    // Load the IDR_MYFRAME menu.
    pNewMenu = new CMenu;
    pNewMenu->LoadMenu(IDR_MYFRAME);
    // Set the mainframe menu to mainframe.
    ((CMainFrame *)AfxGetMainWnd())->SetMenu(pNewMenu);
    return TRUE;
}

And

void CMydlg::OnClose()
{
    // Detach the previous HMenu handle from the object.
    pNewMenu->Detach();
    pNewMenu->LoadMenu(IDR_MAINFRAME);
    // Restore the mainframe menu.
    ((CMainFrame *)AfxGetMainWnd())->SetMenu(pNewMenu);
    CDialog::OnClose();
}

If there are other methods of closing the dialog (for example, by clicking a button in the dialog), then the code given above in the OnClose handler must be put in the button click handler.

Sanjeev Kumar, MSMFC, 6/23/95

Windows Common Controls (aka Windows 95 Controls)

Can I use these controls under Windows NT or Win32s?

Windows NT version 3.50 does not support the common controls, and will not in the future. You must use Windows NT version 3.51 to gain the common controls.

blaszczak@BIX.com, mfc-l, 7/6/95

Version 1.30 of Win32s supports the common controls.

Where's a demo of these wickedly cool controls?

Check out the MFC sample, FIRE, which features most of the controls in action: MSVC20\samples\mfc\fire. Under version 4.0, there's another one called CMNCTRLS.

Scot Wingo, scot@stingsoft.com, 7/27/95

How do you handle NM_DBLCLK for a CListCtl?

BEGIN_MESSAGE_MAP(CListView, CView)
    ON_NOTIFY( NM_DBLCLK,ID_LISTCTRL,OnDblClick )
END_MESSAGE_MAP()
void CListView::OnDblClick(NMHDR* /*k*/, LRESULT* /*j*/)
{
    int nItem, nFlags;
    char szTest[80];
    nFlags = LVNI_SELECTED;
    nItem = m_ListCtrl->GetNextItem(-1, nFlags );
    if ( nItem != -1 )
    {
        sprintf( szTest, "Selected Item %d", nItem);
        AfxMessageBox(szTest);
    }
}

spolyak@interaccess.com, mfc-l, 7/21/95

Does CTreeCtrl support multiple selection?

No. Sorry! (I see this one all the time!)

Scot Wingo, scot@stingsoft.com

If it's accessible to you, Microsoft Systems Journal, July 1994, has an extensive look at TreeViews, including a sample program that includes drag-and-drop. [MSDN editor’s note   You can find this in the Library under Books and Periodicals, Microsoft Systems Journal, 1994 Volume 9.] ]If you're developing for Windows 95, you don't need a shareware implementation—MFC has a class for it.

steven@primenet.com

When I expand a node in my CTreeCtrl, there's no visual feedback—what to do?

Create the control with TVS_SHOWSELALWAYS style.

kfreeman@viewlogic.com

How do I implement multiple selection, ToolTips, editable nodes, and multiple columns in my tree control?

Unfortunately, because the tree control lives in a binary DLL, it is not very extensible and you are stuck without these features. There have been articles on how to try and "hack" these features, but they do not work reliably.

Stingray Software has a drop-in tree control replacement that implements all of these features and more in Objective Toolkit. Demos are at http://www.stingsoft.com/.

Scot Wingo, scot@stingsoft.com

CSplitterWnd FAQs

We would like to add lots of CSplitterWnd questions to this FAQ—email your toughest ones to mfc_faq@stingsoft.com.

FYI: MFC Internals, written by George Shepherd and me, has a whole chapter devoted to this—it's my personal favorite MFC class because it has lots of interesting internals, shortcomings, odd behaviors, and so forth.

We wrote a Dr. Dobbs Journal article where we show how to swap the splitter from horizontal to vertical. I think the code is at http://www.ddj.com, if you are interested.

Scot Wingo, scot@stingsoft.com

Views, Documents, and Frame Class Questions

Views
Documents

Views

How do I size a view?

Normally, you can change the size of a window by calling MoveWindow(). In an application developed with the Microsoft Foundation Class (MFC) Library, the view window is a child window of the frame window that surrounds the view. To change the size of the view window, retrieve a pointer to the frame window of the view by calling GetParentFrame(), then call MoveWindow() to change the size of the parent. When the parent frame window changes size, it automatically changes the size of the view window to fit in the parent frame.

Visual C++ Knowledge Base article Q109039, 6/4/94

How do I size a CFormView?

See the Visual C++ Knowledge Base article Q98598, "Using CFormView in SDI and MDI Applications," for a very long answer. Basically, you need to override OnInitialUpdate() in a CFormView derived class. There's other details to deriving from CFormView that the article goes into.

Visual C++ Knowledge Base article Q98598, 6/7/95

In the view ClikethisView declaration:

virtual void OnInitialUpdate();

In the ClikethisView code:

void ClikethisView::OnInitialUpdate()
{
    // Make the window the size of the main dialog.
    CFormView::OnInitialUpdate();
    GetParentFrame()->RecalcLayout();
    ResizeParentToFit( /*FALSE*/ );
}

andyr@gate.net, programmer.misc, 8/11/95

How do I use new views with a doc template?

In an application created with AppWizard, you have two options: Change the derivation of the current view, or create a new view and use the new view in your MDI application along with the original view.

To create a new view, use ClassWizard to create a new class derived from CView. After the class has been created, the steps to use the new view or to modify the view provided by AppWizard are the same.

  1. Modify the header file for the view class to change all references to CView to the name of the desired view class. In this example, the class is derived from CScrollView. Usually, this step involves changing the class the view class is derived from as follows:
    class CMyView : public CScrollView
    
  2. Modify the implementation file for the view class to change all references to CView to the name of the desired view class. This involves changing the IMPLEMENT_DYNCREATE line as follows:
    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.

  3. No further modifications are required if you are modifying a view created by App Wizard. If you create a new view, find the AddDocTemplate() call in the CWinApp::InitInstance() function. The third parameter to AddDocTemplate() is RUNTIME_CLASS(CSomeView). To replace the current view with the new view class, change CSomeView to CMyView. In an MDI application, you can use multiple view types by adding a second AddDocTemplate() call that changes RUNTIME_CLASS(CSomeView) to RUNTIME_CLASS(CMyView).

For more information, please see Knowledge Base article Q99562, "Switching Views in a Single Document Interface Program."

Visual C++ Knowledge Base article Q99562, 6/7/95

How do I change the background color of a view?

To change the background color for a CView, CFrameWnd, or CWnd object, process the WM_ERASEBKGND message. The following code shows how:

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;
}

I solved the problem like this:

HBRUSH dlgtest::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    switch (nCtlColor)
    {
        case CTLCOLOR_BTN:
        case CTLCOLOR_STATIC:
        {
            pDC->SetBkMode(TRANSPARENT);
        }
        case CTLCOLOR_DLG:
        {
            CBrush*     back_brush;
            COLORREF    color;
            color = (COLORREF) GetSysColor(COLOR_BTNFACE);
            back_brush = new CBrush(color);
            return (HBRUSH) (back_brush->m_hObject);
        }
    }
    return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
}

Tim, tfiner@vrli.com, email, 9/10/95

How do I get the current view?

The best thing to do is to pass the view along as a parameter. If this is impractical, you can get the view if you know that it is the currently active document and the currently active view. For details, see the Visual C++ Knowledge Base article Q108587, "Get Current CDocument or CView from Anywhere."

In brief, use

    ((CFrameWnd*) AfxGetApp()->m_pMainWnd))->GetActiveDocument()

and

    ((CFrameWnd*)(AfxGetApp()->m_pMainWnd))->GetActiveView()

to get the document and the view. It might be a good idea to wrap them in static functions in your CMyDoc and CMyView and check that they are of the correct RUNTIME_CLASS.

However, if the view isn't the currently active view or if you can run OLE in place, this won't work.

null@diku.dk, programmer.misc, 6/8/95

How do I create multiple views on one document?

The CDocTemplate::CreateNewFrame() function creates additional views of a document in an MDI application written with MFC. To call this function, specify a pointer to a CDocument object (the document for which the function will create a view) and a pointer to a frame window that has the properties to duplicate. Typically, the second parameter of this function is NULL.

When an application calls CreateNewFrame(), the function creates a new frame window and a view in the frame window. The frame window type and view type depend on the document template (CDocTemplate) associated with the document specified in the CreateNewFrame() call.

The CHKBOOK MFC sample application that ships with Visual C++ also demonstrates creating additional frames and views for documents. Check out CHKBOOK.CPP, the CChkBookApp::OpenDocumentfile() function.

Another example of using CreateNewFrame() is the MULTVIEW sample application.

CreateNewFrame() creates both a frame and a view; not only a view. If, for some reason, CreateNewFrame() does not quite address your situation, the source code for CreateNewFrame() is quite useful to demonstrate the steps required to create frames and views.

Visual C++ Knowledge Base article Q100993 with mods, 6/25/95

How do I get all the views in an MDI app?

You need to use some functions that are undocumented:

You'll also need to mess with the m_templateList member of CWinApp.

blaszczak@Bix.com, mfc-l, 7/11/95

Note   This has changed with MFC version 4.0. There's now a class called CDocManager that can get to all of the views/docs for you. Check out MFC Internals for details.

Scot Wingo, scot@stingsoft.com

How do I make a CScrollView "mouse scrollable"?

Download AUTOSV.LZH from the MSMFC library on CIS. This code shows you how to implement a secondary message loop, taking care of the mouse activity. Hooks are provided to customize the code. Freeware.

Patrick Philippot, CIS email, 8/3/95

Documents

Do I have to use the document/view architecture?

MFC does not force you to use document/views. Check out the HELLO, MDI, and HELLOAPP samples—they don't use it at all. Most MFC features can be used in non-document/view applications. You do lose features like print preview and many OLE features when you don't go document/view.

Scot Wingo, scot@stingsoft.com, 6/7/95

How do I get the current document?

See "How do I get the current view?" for details.

When are documents destroyed?

In SDI applications, the document is deleted when the application exits. In MDI applications, the document is deleted when the last view on the document is closed. To help keep your document SDI/MDI compatible, you should delete the document's data in the virtual DeleteContents() function, not in the destructor.

Richard Hazenberg, drmcode@euronet.nl, programmer.misc, 6/24/95

How do I create multiple documents?

To add support for additional document types, you can create and register additional CMultiDocTemplate objects with your CWinApp derived object. This technique is illustrated in the MULTDOCS sample application. The general steps needed to add an additional document type to an MFC application are listed below.

  1. Use AppWizard to create a new document class and a new view class.

  2. Use the Resource Editor to add a new resource string to support the new document class. For more information on the format of the document template string resource, see the topic "How to Interpret a Document Template String."

  3. Use the Resource Editor to add an additional icon and menu resource to the application. Note that the ID for each of these resources needs to be the same ID as the resource ID used for the document template string created in Step 2. This ID is used by the CMultiDocTemplate class to identify the resources associated with the additional document type.

  4. In the application's InitInstance() function, create another CMultiDocTemplate object and register it with the CWinApp::AddDocTemplate() function. For example:
    CMultiDocTemplate* pDocTemplate2 = new CMultiDocTemplate(
    IDR_DOC2TYPE, RUNTIME_CLASS(CDoc2),
    RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CView2));
    AddDocTemplate(pDocTemplate2);
    

And finally, add the custom serialization and painting code to your new document and view classes.

MS FAQ, 6/25/95

How do I get a list of open documents?

The code below demonstrates how to retrieve a list of pointers to all CDocuments that were created using a CDocTemplate object.

In the code below, CMyApp is derived from CWinApp. The variable m_templateList is a CPtrList object that is a member of CWinApp, and it contains a list of pointers to all of the document templates (CDocTemplates). The CDocTemplate functions GetFirstDocPosition() and GetNextDoc() are used to iterate through the list of documents for each document template.

void CMyApp::GetDocumentList(CObList * pDocList)
{
    ASSERT(pDocList->IsEmpty());
    POSITION pos = m_templateList.GetHeadPosition();
    while (pos)
    {
        CDocTemplate* pTemplate = 
            (CDocTemplate*)m_templateList.GetNext(pos);
        POSITION pos2 = pTemplate->GetFirstDocPosition();
        while (pos2) 
        {
            CDocument * pDocument;
            if ((pDocument=pTemplate->GetNextDoc(pos2)) != NULL)
                pDocList->AddHead(pDocument);
        }
    }
}

There are two public member functions of the CDocTemplate class that are not documented in the reference manual or the online help. However, these are public member functions defined in the CDocTemplate class and provide simple functionality for traversing the list of open documents. These functions operate as follows:

Function Virtual POSITION GetFirstDocPosition() const;
Remarks Call this function to get the position of the first document in the list of open documents associated with the template.
Return Value A POSITION value that can be used for iteration with the GetNextDoc member function.
Function Virtual CDocument* GetNextDoc(POSITION& rPosition) const;
rPosition A reference to a POSITION value returned by a previous call to the GetNextDoc or GetFirstDocPosition member function. This value must not be NULL.
Remarks Call this function to iterate through all of the document template's open documents. The function returns the document identified by rPosition and then sets rPosition to the POSITION value of the next document in the list. If the retrieved document is the last in the list, then rPosition is set to NULL.
Return Value A pointer to the view identified by rPosition.

Visual C++ Knowledge Base article Q106455, 6/25/95

Note that this is only valid for MFC version 3.2 and lower; MFC version 4.0 follows:

void CMyApp::DoSomethingToAllDocs()
{
    CObList  pDocList;
    POSITION pos = GetFirstDocTemplatePosition();
    while(pos)
    {
        CDocTemplate* pTemplate = GetNextDocTemplate(pos); 
        POSITION pos2 = pTemplate->GetFirstDocPosition();
        while(pos2)
        {
            CDocument* pDocument;
            if(pDocument = pTemplate->GetNextDoc(pos2))
                pDocList.AddHead(pDocument);
        }
    }
    if(!pDocList.IsEmpty()){
        pos = pDocList.GetHeadPosition();
    while(pos)
    {  
        // Call some CDocument function for each document.
        ( (CDocument*)pDocList.GetNext(pos) )
            ->UpdateAllViews(NULL);
    }
}

mcontest@universal.com, email, 9/22/95

How do I keep my application from creating a new document at startup?

Add this call:

cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing

just before the call to ProcessShellCommand in the app's InitInstance.

lechner-cos1@kaman.com, email, 1/6/96

OLE Class Questions

Structured Storage/Compound Files
OLE Controls (Previously Called OCXs)

Structured Storage/Compound Files

When I upgraded, I could not read my files generated by the old version of MFC. What do I do?

There may be an easier way, but here is how I did it:

Use VERSIONABLE_SCHEMA and GetObjectSchema to identify the version. If it is an old version, then it is stored in OLE version 1.0 format. To read this format, first read a WORD and a CString (type and name info). Next is the OLE data itself (the hard part). Use the following steps:

  1. Use StgCreateDocfile to create a temporary Compound File.

  2. Use OleConvertOLESTREAMToIStorage to copy the data to the Compound file, converting to OLE version 2.0 format.

  3. Call OleLoad using the IStorage to get an IUnknown pointer, then call QueryInterface to set the COleClientItem::m_lpObject member, and set m_nDrawAspect to DVASPECT_CONTENT.

  4. Release the IUnknown pointer and the IStorage pointer.

  5. The OleConvertOLESTREAMToIStorage code requires an OLESTREAM implementation. Copy the code from Visual C++ 1.0 MFC code.

This actually works. There are some issues with messing with the schema parameter, and I have not implemented writing OLE 1/MFC files. Code available on request.

Ron Jones, ronjones@xnet.com, via programmer.tools, 5/9/95

OLE Controls (Previously Called OCXs)

What is an OLE control?

OLE controls are the 32-bit successor to 16-bit VBX controls. Instead of being stored in a plain DLL and having functional interfaces, OLE controls rely on OLE Automation. Hopefully, this will make the interface more flexible and easier to use than VBXs.

Although OLE controls use OLE, they are not object oriented. There is a flat set of properties you have access to and you can not apply OO techniques such as inheritance, polymorphism, etc., to them. In my opinion, this can be pretty frustrating to the MFC programmer who is used to the OO techniques.

Scot Wingo, scot@stingsoft.com, 6/25/95

How do I write OLE controls?

In Visual C++ 2.x, Microsoft released the OLE Control Developer's Kit (CDK). You use that kit and its tools to write OLE controls. In Visual C++ 4.0, this is no longer separate and you now just run the Control Wizard. Check your Visual C++ documentation for more info.

Scot Wingo, scot@stingsoft.com, 6/25/95

What versions of MFC support OLE control containment?

MFC 4.0 supports OLE control containment. Earlier versions of MFC don't unless you roll your own. (Yuck!)

How do I get application-specific control bars to disappear when editing in place?

Add CBRS_HIDE_INPLACE to Create() of the toolbar.

Example:

m_wndFormBar.Create(this,
    WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_HIDE_INPLACE,IDW_FORMBAR)

Paul Rony, 102615.601@compuserve.com

WOSA Class Questions

CRecordSet
WinSock

CRecordSet

When I add a CRecordSet class, I get tons of linker errors.

If you haven't told AppWizard to use Database Support when you created your project, AppWizard doesn't include the database headers. If you add "#include" in your stdafx.h, CRecordSet will be "legalized." Then open the Linker Options window and add the library: "odbc". This avoids tons of linker errors.

Wolfgang Bessler, bessler@highland.swb.de, comp.lang.c++, 6/5/95

I need a CRecordSet::Find(). What should I do?

Use the WHERE clause in SQL.

mikeblas@interserv.com, mfc-l, 10/10/95

WinSock

I'm having problems with CSocket blocking—what's up?

I've worked around this by creating a dialog box that I pop up after calling Connect(). For example:

CMySocket MySocket;
MySocket.Create();
MySocket.Connect("mysmtphost",25);
DummyDlg DummyDialog;
MySocket.m_pDialog=&DummyDialog;
DummyDialog.DoModal();

This suspends the thread until MySocket sends a WM_CLOSE message to DummyDialog. I'd rather it look like:

MySocket.m_hEvent=CreateEvent(...);
WaitForSingleObject(MySocket.m_hEvent,INFINITE);

But that stops all processing of MySocket.

Cynthia Jennings (idlewild@is.net), programmer.win32, 6/19/95

DLL and Build Questions

If you have questions about extension and user DLLs, be sure to read MFC 3.1 Technical Notes 11 and 33. Volume 2 of the documentation has more info too. Finally, try searching on the sample names DLLHUSK (extension DLL) and DLLTRACE (user DLL) in Books Online.

Do I need a CWinApp object in a DLL?

The Microsoft Foundation Class Library supports two types of DLLs: _USRDLL and _AFXDLL. The _USRDLL model requires one CWinApp object to perform the initialization and cleanup of the Microsoft Foundation Class Library Windows classes that the DLL uses. This requirement is described in MFC Tech Note 11; the DLLTRACE sample demonstrates a _USRDLL that contains a CWinApp object.

An _AFXDLL does not require a CWinApp object. Because it shares the Microsoft Foundation Class Library classes with the application, it does not require a CWinApp to provide initialization and cleanup. Instead, an _AFXDLL requires a special version of LibMain() and a DLL initialization function.

Visual C++ Knowledge Base article Q109031, 6/4/95

How should I define the WEP in a MFC DLL?

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.

See Visual C++ Knowledge Base article Q98374 and Technical Notes 11 and 33.

Visual C++ Knowledge Base article Q98374, 6/7/95

How do I build an "extension DLL"?

  1. When you're building a 32-bit extension DLL, define _AFXEXT on the compiler command line. If you look in AFXVER_.H, you'll see that this forces _AFXDLL to also be defined. So an "AFXEXT" DLL is an AFXDLL.

  2. When _AFXDLL is defined, AfxGetResourceHandle returns a value stored in MFC's global data, which is shared by the .EXE, the extension DLL, and the MFC DLL. The handle returned identifies the module that will be searched first when looking for a resource.

    (See the source code for AfxFindResourceHandle() if you're curious about the order of the search.)

  3. Strictly speaking, what we need to load a resource is a module handle rather than an instance handle. (Instances share modules—that is, code and resources—but have different data.) A DLL has a module handle that is distinct from the handle of the .EXE.

  4. You can use ::GetModuleHandle to get the handle for your DLL, then pass it to AfxSetResourceHandle so that your DLL is the first place searched for resources. But note that this removes the .EXE module from modules searched. You'll probably want to save a copy of the handle returned by AfxGetResourceHandle before calling AfxSetResourceHandle, then restore it once you're done loading the DLL resource.

Charlie Kester, Microsoft Developer Support, MSMFC, 7/19/95

How can I manage resources in a resource-only DLL and still benefit from ClassWizard?

zThe following text is available as RESDLL.ZIP in the MSMFC library on CompuServe (applies to Visual C++ version 2.0):

"How To Manage An MFC Project Storing Its Resources Into A Resource-Only DLL"

Software localization is much easier when your project stores its resources in a resource-only DLL. There are also many situations where storing the project's resources in a DLL can be a good idea.

However, if this project is an MFC project, doing so will generate a major drawback: You will not benefit from the ClassWizard capabilities any longer because the resources will be managed in a separate project.

However, there's a trick that you can use to develop your project as if it were a standard project, while being able to quickly switch to the resource-only DLL model. Here's how to proceed:

Method 1

  1. Create your project as usual using AppWizard (we'll name it TEST).

  2. Close the project and create a new DLL project in the same directory (call it RESDLL). When you click on the Create button, Visual C++ opens the Add file dialog. Take this opportunity to add the resource file of the previous project (TEST.RC) to this new project.

  3. Before being able to compile the resources of the TEST project as a resource-only DLL, you must add the /NOENTRY option to the linker. Unfortunately, the Settings dialog box of Visual C++ doesn't allow you to do that in a simple way:

    Select Project|Settings from the man menu.

    Click the Link tab.

    Select General from the Category combo box.

    In the Object/Library Modules field, remove all references to any .LIB file (they are useless) and add /NOENTRY. This option should then appear in the Common Options display area.

    Click OK and compile. You now have a DLL containing only the resources for your project.

  4. Do not open the TEST.MAK project. Instead, copy TEST.MAK to TEST_RES.MAK in your project directory.

  5. Open TEST_RES.MAK and remove TEST.RC from the project files.

  6. Select Project|Settings, click on the General tab, and add "USE_RESDLL" to the list of Preprocessor Definitions.

  7. Open TEST.H and modify the class declaration of CTestApp this way:
    public:
    CTestApp();
    #ifdef USE_RESDLL
    public:
    virtual int ExitInstance();
    private:
    HINSTANCE m_hInstDLL;
    #endif // USE_RESDLL
    
  8. Open TEST.CPP and modify CTestApp::InitInstance as follows. Also, add the newly declared ExitInstance member function:
    BOOL CTestApp::InitInstance()
    {
    // Standard initialization.
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need.
    #ifdef USE_RESDLL
    if ((m_hInstDLL = LoadLibrary("resdll.dll")) == NULL)
    {
    return FALSE; // Failed to load the localized resources.
    }
    else
    {
    AfxSetResourceHandle(m_hInstDLL); 
    // Get resources from the DLL.
    }
    #endif
    // ....
    #ifdef USE_RESDLL
    int CTestApp::ExitInstance()
    {
    FreeLibrary(m_hInstDLL);
    return CWinApp::ExitInstance();
    }
    #endif
    
  9. Compile. TEST_RES.EXE should work very nicely, loading its resources from the DLL.

  10. Close the project and open TEST.MAK. Compile. TEST.EXE should also work very well but this time, the resources are loaded from the .EXE file because you have not defined USE_RESDLL in this version of the project.

Warning   When switching from one model to another, you must either Rebuild All or touch TEST.CPP. Otherwise, you'll have problems.

Now, you are able to modify your resources and to use ClassWizard when you work with TEST.MAK. To build the resource-only DLL version of the project, just switch to TEST_RES.MAK after recompiling RESDLL (RESDLL.MAK) if changes have been made to the resources.

It's that easy!

Method 2

  1. Proceed as above in Steps 1, 2, and 3.

  2. Instead of creating a new project, copy TEST.RC to RESDLL.RC. Remove TEST.RC from your project and add RESDLL.RC. A different name is somewhat safer.

  3. Double-click RESDLL.RC to trigger a rebuild of the .CLW file.

  4. Apply the "Exclude File from Build" command to RESDLL.RC. (Project|Settings, General Page, "Exclude File From Build")

  5. Delete TEST.CLW and TEST.RC.

Now TEST and RESDLL will work together through the ClassWizard. The resources defined in RESDLL.RC will not be added to TEST.EXE. This method is simpler but doesn't allow you to test your program in both cases (resources in the DLL or resources linked to the .EXE file). I prefer the latter when developing because I do not have to bother about orphaned DLLs when a GPF occurs (although this is less a problem under Windows NT).

Don't forget to recompile the DLL before testing your program each time you modify the resources. A batch file calling NMAKE installed in the Tools menu will certainly be faster than switching from project to project. Using the "New Target" facility won't help in that case.

It would be nice if Visual C++ had the same capability as Borland C++: a project can contain multiple independent targets. So, the developer is able to manage DLL and .EXE creation from within the same project.

Patrick Philippot, CIS email, 8/3/95

I am having some problems with exports/imports and extension DLLs. Where can I go for help?

This is a very complex subject. George Shepard and I actually wrote about this in our "MFC Internals" column in Visual C++ Developer's Journal, at http://www.vcdj.com. Also, Chapter 9 of our book, MFC Internals, covers MFC and DLLs (extension and regular) in great detail.

Scot Wingo, scot@stingsoft.com

MFC Tips, Tricks, and Caveats

What's the best way to convert my C Windows App to MFC?

Microsoft and Symantec have jointly developed a tool that helps you make the move from a C Windows application to MFC. It's called the MFC Migration Kit. You can find it on the Visual C++ 2.x CD-ROM in the MFCKIT directory. The kit is also available from the Microsoft Software Library and from Symantec.

Why is my MFC application running slow?

MFC apps should be nice and snappy. Make sure you are not building the debug version and that you have the trace options off (MFCTRACE.EXE). If your application continues to be slow, try doing some quick profiling to see if you are making any redundant calls.

Scot Wingo, scot@stingsoft.com, 5/31/95

How can I create an application that is initially maximized?

For new applications, this can be done with AppWizard during Step 4. During Step 4, select Advanced, and then choose the Main Frame tab. Check the Maximized option.

For an MDI application, in the CWinApp::InitInstance() function, set CWinApp::m_nCmdShow to SW_SHOWMAXIMIZED before calling pMainFrame->ShowWindow(m_nCmdShow). In an application generated by AppWizard, the code is as follows:

// 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();

Visual C++ Knowledge Base article Q109039, 6/4/95

How do I enable TRACE macros in my app?

If you use Visual C++ 1.0, run the TRACER application from your Microsoft Visual C++ program group (its icon has the title "MFC Trace Options"). Select "Enable Tracing," then choose OK.

If you use Microsoft C/C++ 7.0, you must copy the AFX.INI file from the Microsoft Foundation Class Library source directory (by default, C:\C700\MFC\SRC) to your Windows directory (by default, C:\WINDOWS). This file should contain a section such as the following:

[Diagnostics]
   TraceEnabled = 1
   TraceFlags = 0

As long as TraceEnabled is set to 1, tracing is enabled.

This AFX.INI file is the same for both C/C++ 7.0 and Visual C++ 1.0. In Visual C++ 2.x, the TRACE output automatically goes to the 'Debug' window when you run in the debugger.

Visual C++ Knowledge Base article Q109039, 6/7/95

How do I perform background processing in my application?

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.

See Visual C++ Knowledge Base Q99999 for more info.

Visual C++ Knowledge Base article Q99999, 6/7/95

How do I send a message to another thread?

Try using SendNotifyMessage() to send messages to another thread.

null@diku.dk, via programmer.misc, 6/18/95

Does Microsoft use MFC in their products? Which ones?

There are many Microsoft apps written in MFC. Sometimes it's just not obvious. (To name a few: Bookshelf, Bob, WordArt OLE server, Visual C++ (of course), Windows 95 Paint, Windows 95 WordPad, some portions of Windows 95 FAX software, some Windows 95 games I know of....)

In the future, there are more apps coming out using MFC. I don't have a way to track all of these uses, so there is certainly more that I'm not aware of or can't remember. I don't expect Word or Excel to ever use MFC—they have way too much legacy code and they don't see any customer benefit to rewriting to MFC. But my point is—definitely for new code, Microsoft is using MFC. Even some "old" code is taking advantage of MFC in future versions.

Dean McCrory, MSMFC, 6/8/95

How do I limit my MFC application to one instance?

Look at the Microsoft C++ sample ONETIME.

In brief:

const char* MyMainWndClassName = "MyMainWndXQW"
BOOL CMyApp::InitApplication()
{
    // Call base class. Default version does nothing.
    CWinApp::InitApplication();
    WNDCLASS wndcls;
    // Start with NULL defaults.
    memset(&wndcls, 0, sizeof(WNDCLASS));   
    // Get class information for default window class.
    ::GetClassInfo(AfxGetInstanceHandle(),"AfxFrameOrView",&wndcls);
    // Substitute unique class name for new class.
    wndcls.lpszClassName = MyMainWndClassName;
    // Register new class and return the result code.
    return ::RegisterClass(&wndcls);
}

And:

BOOL CMyApp::FirstInstance()
{
    CWnd *PrevCWnd, *ChildCWnd;
    // Determine if another window with our class name exists.
    PrevCWnd = CWnd::FindWindow(MyMainWndClassName, NULL);
    if (PrevCWnd != NULL)
    {
        // If so, does it have any pop-ups?
        ChildCWnd=PrevCWnd->GetLastActivePopup();
        // Bring the main window to the top.
        PrevCWnd->BringWindowToTop();
        // If iconic, restore the main window.
        if (PrevCWnd->IsIconic())
            PrevCWnd->ShowWindow(SW_RESTORE);
        // If there are pop-ups, bring them along too!
        if (PrevCWnd != ChildCWnd)
            ChildCWnd->BringWindowToTop();
        // Return FALSE. This isn't the first instance
        // and we are done activating the previous one.
        return FALSE;
    }
    else
        // First instance. Proceed as normal.
        return TRUE;
}
CMyApp::InitInstance()
{
    if (!FirstInstance()) 
        return FALSE;
    // ...
}

null@diku.dk, programmer.tools, 6/19/95

See also Win32 SDK Knowledge Base article Q124134 ("Allowing Only One Application Instance on Win32s") and Jeffrey Richter's Advanced Windows NT, chapter 7, "Prohibiting Multiple Instances of an Application from Running: The MultInst Sample Application" (available on the MSDN Library CD).

null@diku.dk, email, 8/8/95

Update—these were posted to mfc-l:

I have each InitApplication() create a semaphore. If GetLastError() returns ERROR_ALREADY_EXISTS then I know that some other application is already running and has gotten that far, so I bail.

Yourapp::InitInstance()
{
    hMutexOneInstance = 
    CreateMutex(NULL,TRUE,_T("PreventSecondInstance"));
    if(GetLastError() == ERROR_ALREADY_EXISTS)
        bFound = TRUE;
    if(hMutexOneInstance) 
        ReleaseMutex(hMutexOneInstance);
    return (bFound == TRUE) ? FALSE : TRUE;
}

mcontest@universal.com

There is a nice section in Jeffrey Richter's book Advanced Windows NT about this. Essentially, it uses shared data segments between processes.

  1. In your main file, add:
    #pragma data_seg(".SharedData") 
    LONG nUsageCount = -1; 
    #pragma data_seg() 
    
  2. In your Application's InitInstance(), call:
    InterlockedIncrement ( &nUsageCount ); 
    

    This function returns the incremented value of the variable. If it is nonzero, you know that you are not the first App.

  3. In your Application's ExitInstance(), call:
    InterlockedDecrement( &nUsageCount ); 
    
  4. In your .DEF file, have the following lines (note that the segment name you give here should match the one in the application's main file):
    SEGMENTS 
        .SharedData shared 
    

abalakri@us.oracle.com

You'd better use one of the built-in synchronization methods. See the Win32 Knowledge Base article Q124134, "Allowing Only One Application Instance on Win32s," for a sample of using a memory-mapped file for synchronization. It doesn't include starting the previous instance, but if you detect that you're not the only one running, it should be pretty simple: If CreateFileMapping fails, try to find the previous instance from the window class name. If it's not found, sleep for a while and start over (with CreateFileMapping). In this way, either you will find the other instance when it gets around to creating its window or CreateFileMapping will eventually succeed. The advantage of using CreateFileMapping instead of CreateObject is that it also works on Win32s.

nuj@kruger.dk

Note   There's a sample of this that was contributed by john@jing.com (John Xu) called onetime4.zip that is in the MFC FAQ archive.

How do I get my MFC app to use the Registry on Win32 platforms?

Just make a call to SetRegistryKey("MyCompany") in your CWinApp class and pass it a string (typically your company name). This string will define where in the registry the data goes: HKEY_CURRENT_USER\Software\MyCompany\\\

After making this call just use the normal WriteProfilexxx() routines and the data will go to the registry instead of to an .INI file. It works well and is simple!

Brett Robichaud, brett_robichaud@tallysys.com programmer.win32, 6/23/95

How do I programmatically terminate my MFC application?

MFC does not provide a public function to gracefully exit an application. A method for dealing with this is to create a function in your application like the following:

void ExitApp()
{
    // Same as double-clicking on main window close box.
    ASSERT(AfxGetApp()->m_pMainWnd != NULL);
    AfxGetApp()->m_pMainWnd->SendMessage(WM_CLOSE);
}

As you can see, this is implemented as a global function, which can be called from anywhere in your application. It simply sends a WM_CLOSE message to your application's mainframe window. This initiates an orderly shutdown of the application.

If you are using MFC version 2.5 or later, you can take advantage of a new global MFC function, "AfxGetMainWnd", to simplify the code:

void ExitMFCApp()
{
    // Same as double-clicking on main window close box.
    ASSERT(AfxGetMainWnd() != NULL);
    AfxGetMainWnd()->SendMessage(WM_CLOSE);
}

Note   Always call CDocument::SetModifiedFlag() after changing your document data. This will ensure that the framework prompts the user to save before shutdown. If you need more extensive control over the shutdown procedure, you can override CDocument::SaveModified().

Visual C++ Knowledge Base article Q117320, 6/25/95

What's the difference between IMPLEMENT_DYNAMIC, IMPLEMENT_DYNCREATE, and IMPLEMENT_SERIAL?

IMPLEMENT_DYNAMIC provides run-time type information to support macros such as IsKindOf and GetRuntimeClass.

IMPLEMENT_DYNCREATE adds the ability to allow MFC to create the type on the fly. This is required for any concrete data type that will be serialized to a file.

IMPLEMENT_SERIAL also provides a version number for the class and adds the ability to use the >> operator to read the type from a file.

As an example, if a derived class Dog uses IMPLEMENT_DYNCREATE and a base class Animal uses IMPLEMENT_SERIAL, then a Dog can be written with a pointer to either but can only be read by a pointer to Animal.

MFC 3.x provides a constant called VERSIONABLE_SCHEMA to be used with IMPLEMENT_SERIAL to support multiple versions at the same time. The implementation in MFC is broken and fails at run time.

jimb@turningpoint.com, email, 7/11/95

Note   It is not true that the versionable schema is still broken. It has been fixed in MFC 4.0.

MSDN editor's note   At one time versionable schemas did not work as claimed, but this problem has been fixed in MFC version 4.0.

How can I declare an abstract base class to be IMPLEMENT_SERIAL?

You need a special form of IMPLEMENT_SERIAL that looks like this: Use the regular DECLARE_SERIAL, but use IMPLEMENT_SERIAL_ABC shown below instead of IMPLEMENT_SERIAL.

#define IMPLEMENT_SERIAL_ABC(class_name, base_class_name, wSchema)
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, NULL)
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb)
{
    pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); 
        return ar;
}

anonymous

What is afx.inl and afxwin1.inl, etc.?

These files live in the \msvcxx\mfc\include directory and include inline functions. These functions are only "inline" during non-debug (_DEBUG is not defined) builds of MFC. They are prefaced with a special _AFX_INLINE directive that gets turned into "inline" for non-debug builds and '' for debug builds.

MFC does this so that you can debug into the functions in debug mode, but get the benefits of inlining during release builds. That's one of the reasons the library shrinks so much in release build mode.

Scot Wingo, scot@stingsoft.com, 7/20/95

Is MFC available on the Macintosh?

Yes! Microsoft has something called the Visual C++ cross-platform edition. This product lets you cross-compile for the 68000-based Macs and I think they have a PowerPC version coming out soon. Contact Microsoft directly for more info.

Scot Wingo, scot@stingsoft.com, 7/27/95

Is MFC available on OS/2?

No.

How should I learn/start learning MFC?

I see this posted lots. To start with, check out section 2.4.2 of this FAQ—books always help. [MSDN editor's note   see the original version of this FAQ on the Web for this information.] Another good point is that you can't really get down-and-dirty in MFC without knowing and understanding the underlying Windows API, so you might want to start with an overview of that. (The Petzold book is the classic here.) At the very least get a feel for what Windows does and what it's capable of.

Another hint I have is don't rely too much on the Wizards—these are great, but they sometimes shield the newbie too much. Take a look at what AppWizard/ClassWizard has done for you, run the debugger through a mainfrm.cpp, etc. You won't understand what the heck is going on until you understand what your magically generated code is doing.

I thought the Writing Windows Applications with MFC book was a good merge between Petzold and intro MFC stuff. Inside Visual C++ may move too fast for someone who doesn't know Windows already.

Scot Wingo, scot@stingsoft.com, 7/27/95

There's no substitute for paying your dues.

Unfortunately MFC is set up so that you're never done paying your dues. (HAHAHAHA!!!)

raymond@btw.com, mfc-l, 7/23/95

Start with the Visual C++ User's Guide and work your way through the Scribble Tutorial. You get an intro to Visual C++ and MFC and see how they work together. Then there are numerous articles on the MSDN CD-ROM to help with basic concepts. Try searching on MFC and Architecture. Don't shy away from reading the MFC Encyclopedia articles (they take more of a "how-to" approach) and by all means become familiar with the MFC Technical Notes. Also (hint), stay focused on the 32-bit stuff if you're just starting out. There are also a number of excellent  journals out there to help.

billb@microsoft.com, mfc-l, 7/23/95

The important points (of the top of my head) are:

If you're a windows programmer don't worry about graphics. The CDC member functions are an almost direct encapsulation of the Windows functions. Also CWnd encapsulates much of the window manipulation functions.

Learn the document/view architecture: document templates, the interaction between the application, the documents and views (AfxGetApp, GetDocument, UpdateAllViews, etc.).

Learn serialization (Scribble makes a good intro to it). DDX and DDV for dialog boxes: there is a good tech note on this. WM_COMMAND handlers and COMMAND_UI handlers, which allow you to enable/disable menu items as well as to apply check mark and radio button marks on menu items; it also gives you one way to use status bars.

During all this you'll also learn how to use ClassWizard and see how it is integrated with the Editor and Resource Editor. Perhaps as part of the MFC FAQ we could create a list of topics (ordered in terms of importance) to learn? [Sure, this is a good start, no? —Scot]

grimes@parallax.co.uk, mfc-l, 7/24/95

What DLLs should I distribute with my MFC app?

You should review the file REDISTRB.WRI on your Visual C++ CD. This file explains what files are necessary for different kinds of applications; it explains what to do about both Windows files and MFC files.

blaszczak@BIX.com, programmer.tools, 7/9/95

dumpbin /imports myapp.exe dll_one.dll dll_two.dll | grep -i dll and recurse through the DLLs you find. Won't find DLLs loaded by LoadLibrary(), however.

null@diku.dk, programmer.tools, 7/10/95

How do I intercept WM_SETTEXT messages?

Because MFC didn't provide generic support for overriding WM_SETTEXT, you can use OnMessage(WM_SETTEXT, OnSetText) in the message map and then define your own method:

....LRESULT CMyClass::OnSetText(wParam, lParam);
    // ...

jfriend@collabra.com, programmer.tools, 8/17/95

I can't create an instance because of DECLARE_DYNCREATE!

Question: ClassWizard generated a class for me but used DECLARE_DYNCREATE(...) and declared my constructor as protected. Now, when I try to create an instance of the class I get the compiler error:

error C2248: 'CChkTbl::~CChkTbl': cannot access protected member declared in class 'CChkTbl'

Answer: ClassWizard does this because the framework normally handles instantiation for you. I.e., if this is a CView derived class, normally the CDocumentTemplate instantiates the view during the default OnFileNew() or when you call CxxxDocTemplate->OpenDocumentFile() or something similar. The framework does this so that it will give you an error message if you accidentally try to instantiate it yourself. If you really need to do instantiation outside of the CDocTemplate framework, simply change the constructor to be public.

chucks@skypoint.com, programmer.tools, 8/12/95

Answer: The answer is that the DECLARE_DYNCREATE macro lays down a "protected:" directive and leaves it in place. One needs to make sure that anything following DECLARE_DYNCREATE should be "protected" too; if not, one needs to declare "public:" or "private:", as needed.

duane@anasazi.com, email, 8/15/95

What the heck is this _T() thing I keep seeing?

_T is a macro to expand the string literal to support Unicode.

Mike Oliver, MSMFC, 8/1/95

How do I use CMemoryState?

In MFC 2.0 and later built-in diagnostic facilities are provided. Hence it is not necessary to include CMemoryState explicitly in your app. The MFC 2.0 debugging libraries automatically perform memory leak detection. The detection code is in AFXMEM.CPP. This code detects the case in which an application dynamically allocates an object and fails to delete the object before the program terminates.

In fact, CMemoryState may not function properly. You can refer to the Visual C++ Knowledge Base article Q99022, "Foundation Class Debug Library Detects Memory Leaks," for more details.

#define new DEBUG_NEW should be defined in every .CPP source file. Also, insert the following code in InitInstance of the application:

#ifdef _DEBUG
    afxMemDF |= checkAlwaysMemDF;
#endif

You can refer to the Visual C++ Knowledge Base article Q117326, "Foundation Classes Common Asserts, Causes and Solutions," for more details.

Muniraju (NetQuest), MSMFC, 8/1/95

How do I handle my own registered messages?

Editor’s note (Scot Wingo)   In this FAQ, Dean is telling a guy how to handle WM_CHKTBLTOGGLE, which is some message that dude is trying to handle. The guy was doing it a wrong way before—I've left that in for educational reasons.

Use ON_MESSAGE:

    ON_MESSAGE(WM_CHKTBLTOGGLE, OnChkTblToggle)

In your class definition:

    afx_msg LRESULT OnChkTblToggle(WPARAM wParam, LPARAM lParam);

In your message map:

#define ON_WM_CHKTBLTOGGLE()
{
WM_CHKTBLTOGGLE, 0, AfxSig_vwp, (AFX_PMSG)(AFX_PMSGW)(BOOL 
(AFX_MSG_CALL CWnd::*)(BYTE, BYTE))OnChkTblToggle 
},

In your code:

LRESULT CMyView::OnChkTblToggle(WPARAM wParam, LPARAM lParam)
{
    // TODO: write your code here.
}

You told MFC that your function is:

    void CMYView::OnChkTblToggle(UINT, CPoint)

That's what the signature AfxSig_vwp means...and definitely not what you want.

ON_MESSAGE and ON_REGISTERED_MESSAGE are intended to allow you to extend the message handlers to your own custom message handlers. Please don't rely on specific AfxSig_* values or on the message map structure—it may change without notice.

Dean McCrory, mfc-l, 8/19/95

How do I customize the MFC idle time processing?

In my opinion, MFC's idle processing happens too often. Unfortunately, we can't change it because it might break apps when not necessary. But. . . we have built into the code a way for applications to customize the times in which they "enter idle". The secret? CWinThread::IsIdleMessage!

Here's an example that disables idle entry for mouse and timer messages:

BOOL CMyApp::IsIdleMessage(MSG* pMsg)
{
    if (!CWinApp::IsIdleMessage(pMsg))
    return FALSE;
    if ((pMsg->message >= WM_MOUSEFIRST && 
        pMsg->message <= WM_MOUSELAST) ||
        (pMsg->message >= WM_NCMOUSEMOVE && 
        pMsg->message <= WM_NCMBUTTONDBLCLK))
            return FALSE;
    if (pMsg->message == WM_TIMER)
        return FALSE;
    // Otherwise msg must kick in idle processing...
    return TRUE;
}

Now, what would happen if you had a clock on your status bar, and were relying on a WM_TIMER to kick in a call to your update handler for that pane? Well...as you might have guessed, the above code would break you. There is an easy way to fix that, as there is a backdoor method of forcing an idle to kick in: WM_KICKIDLE, defined in afxpriv.h, can be used to make this happen.

So, in your timer handler (most likely a handler in your derived CStatusBar class), you would add some code that does:

if (TimeIsDifferentEnough())
    PostMessage(WM_KICKIDLE);

If you take a look at CWinThread::IsIdleMessage, you'll see that we go through a fair amount of pain to avoid unnecessary OnIdle calls, like checking for mouse moves to the same location as last time. (I don't know why Windows NT does that, but it does—every time the caret flashes.) We are doing just about everything we can without breaking backward compatibility.

deanm@microsoft.com, via email

How do I create nonresizable (static and fixed) splitter bars?

See the Visual C++ Knowledge Base article Q105150, "Preventing Static Splitter Bars from Tracking." It describes how to do this. Basically, derive a class from the CSplitterWnd and override the left button and mouse move messages: call the CWnd versions rather than CSplitterWnd versions. Finally, remove menu items that may generate ID_WINDOW_SPLIT commands.

bills@anest4.anest.ufl.edu, mfc-l, 9/28/95

How do I add "What's this" menus to my application—like Windows 95 hip apps have?

Here are some steps to get you started:

  1. Put the following menu into a resource script:
    IDR_WHAT_IS_THIS_MENU    MENU    DISCARDABLE
    BEGIN
    BEGIN
    POPUP "a"
    BEGIN
    MENUITEM "What's this?", ID_WHAT_IS_THIS
    END
    END
    END
    
  2. Add to your dialog a right-click handler (OnRButtonDown) with menu IDR_WHAT_IS_THIS_MENU. You need to store the point of the last click in some variable—for example,
    CPoint        m_cLastRClickPoint;
    

    and store here the client coordinates of the last right click.

  3. Put the following code into your dialog class (or probably the parent class of all your dialogs):
    BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
        // {{AFX_MSG_MAP(CMyDialog)
        // Whatever
        //}}
        ON_COMMAND(ID_WHAT_IS_THIS, OnWhatIsThis)
    END_MESSAGE_MAP()
    void CMyDialog::OnWhatIsThis()
    {
        CWnd* pControl = ChildWindowFromPoint (m_cLastRClickPoint);
        // If the click wasn't on one of the controls, open Help for dialog.
        if (pControl == NULL || pControl->m_hWnd == m_hWnd)
            WinHelp (HID_BASE_RESOURCE + m_nIDHelp, 
            HELP_CONTEXTPOPUP);
        else
            WinHelp (HID_BASE_CONTROL + pControl->GetDlgCtrlID(),
                HELP_CONTEXTPOPUP);
    }
    

    —and finally add the following lines to the makehelp.bat file:

    echo. >>hlp\wr.hm
    echo // Controls (IDC_*) >>hlp\wr.hm
    makehm IDC_,HIDC_,0x50000 resource.h >>hlp\wr.hm
    

    This wires everything to your Help system.

Poul A. Costinsky, PoulACost@msn.com

How do I display a Choose Directory dialog, instead of a Choose File dialog?

/* Works only if we're Windows 95 capable */
if (afxData.bWin4)
{
    LPMALLOC pMalloc;
    /* Gets the Shell's default allocator */
    if (::SHGetMalloc(&pMalloc) == NOERROR)
    {
        BROWSEINFO bi;
        char pszBuffer[MAX_PATH];
        LPITEMIDLIST pidl;
        // Get help on BROWSEINFO struct - it's got all the bit settings.
        bi.hwndOwner = GetSafeHwnd();
        bi.pidlRoot = NULL;
        bi.pszDisplayName = pszBuffer;
        bi.lpszTitle = _T("Select a Starting Directory");
        bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
        bi.lpfn = NULL;
        bi.lParam = 0;
        // This next call issues the dialog box.
        if ((pidl = ::SHBrowseForFolder(&bi)) != NULL)
        {
            if (::SHGetPathFromIDList(pidl, pszBuffer))
            { 
            // At this point pszBuffer contains the selected path */.
                DoingSomethingUseful(pszBuffer);
            }
            // Free the PIDL allocated by SHBrowseForFolder.
            pMalloc->Free(pidl);
        }
        // Release the shell's allocator.
        pMalloc->Release();
    }
} 

Note   This code will work on Windows 95 only—it's part of the shell.

bradw@netnet.net, mfc-l, 9/9/95

I'm having problems using MFC 4.0 and the STL. What could be wrong?

The trick is to include "new.h" (and also "iostream.h" for similar reasons) before you include any STL headers. For example:

#include <new.h>
#include <iostream.h>
namespace std {
#include <map.h>
}

dave_bickford@compuware.com, mfc-l

How do I make a window stay on top of the others?

SetWindowPos(&wndTopMost,NULL,NULL,NULL,NULL,SWP_NOMOVE|SWP_NOSIZE)

(Like DBWIN does).

lee@usa.nai.net, mfc-l, 1/19/95

How do I make a window move in front of another?

Call either:

SetWindowPos(&wndTop,NULL,NULL,NULL,NULL,SWP_NOMOVE|SWP_NOSIZE)

or

BringWindowToFront();

lee@usa.nai.net, mfc-l, 1/19/95

Is MFC Dead?

No. MFC continues to grow and change as the operating system grows and changes, and as the needs of our users continue to grow and mature. During the summer of 1997, some MFC team members will provide presentations under strict non-disclosure agreements that explain some of the planning that's happening for the next version of the product. The development of the product might change directions to fill an unforeseen pressing need, but the product is by no means dead.

mikeblas@microsoft.com

Does ATL Replace MFC?

No. ATL and MFC are designed to solve two very different problems.

mikeblas@microsoft.com

How do I implement docking windows like Developer Studio has?

MFC does not easily let you do this. The problem is that the dockbar/control bar architecture is built for basic toolbars, not windows. We have solved the problem in our Objective Toolkit product. Our Web site, http://www.stingsoft.com/, has demos and white papers—check it out!

Scot Wingo, scot@stingsoft.com

Will the next version of MFC support [some particular feature]?

The MFC Team increases MFC's feature set as time and resources allow.

MFC features are added when the MFC team feels that MFC can provide a clear win for C++ programmers over using some API or system feature directly. The MFC team tracks features in the operating system as well as new strategic technologies that Microsoft introduces.

Unfortunately, some people in the industry have irresponsibly begun predicting what MFC will or will not support. If someone who is not on the MFC Team claims to know whether MFC will or will not support a particular feature, they're wrong—they don't know. If someone who is on the MFC Team says that the team is planning support for a feature, they're probably right—at that particular moment in time. Because software development schedules change and are influenced by all sorts of surprises, the feature may or may not make the final version of the product, despite the best efforts of the team members.

mikeblas@microsoft.com

Wizard Questions

How can I change the AppWizard options I selected for my application?

Unfortunately, AppWizard will not modify already created and modified applications. You need to generate a new skeleton application using AppWizard and either merge your code into that or compare that skeleton with your original to see what's different. The good news is that it's mostly just a minor tweak to add/remove OLE support, or MDI, or something like that. It usually is just changing your CWinApp derivate, your frame window, or something like that.

Scot Wingo, scot@stingsoft.com, 5/31/95

Visual C++ Questions

Windows 95 Questions
Configuration Questions
Language Feature Questions
Religious Questions
Advanced Visual C++ Tips and Tricks
Miscellaneous Visual C++ Questions
Visual C++/MFC 4.0 Specific Hints, Problems, etc.

I'm trying to keep these as generic as possible, but these types of questions tend to be very release-specific, so where possible, I've included the version that's being questioned.

Windows 95 Questions

I'm running Visual C++ 2.0 and I can't get the Windows 95 look and feel in my dialogs. What's wrong?

In Visual C++ version 2.0, go to the Project/Options dialog, select "Linker" and change the linker command line to include: /subsystem:windows,4.0. This is the default in Visual C++ version 2.1.

Chris Marriott, chris@chrism.demon.co.uk, programmer.misc, 5/25/95

When I compile under Windows 95, it flashes in and out of DOS mode.

Remove or rename any dosprmpt.pif files in your Windows 95 and Windows directories. If this doesn't work, do the same with all .pif files.

Scot Wingo, scot@stingsoft.com, 5/25/95

In the \Win95\system directory there is a .pif for Conagent. It is this .pif file that a person has to change to Window screen mode instead of Full Screen mode. Worked like a charm on mine after running about a month with the screen blanking....

RockyMoore@aol.com, email, 7/16/95

Can Visual C++ 1.5 or 2.0 be used for Windows 95?

You can run both versions under Windows 95. Visual C++ versions 1.5x can only generate 16-bit applications. You can run these on Windows 95, but it's more desirable to have true 32-bit applications, which Visual C++ version 2.0 generates. These same rules apply to Windows NT.

Scot Wingo, scot@stingsoft.com, 6/5/95

Configuration Questions

What are the memory requirements of Visual C++?

Visual C++ version 1.5.x will work on a 486-class machine with a minimum of 4 MB of RAM. 8 MB will make your life much better. Visual C++ version 2.x needs at least 16 MB. Microsoft recommends 20 MB on the box.

Note   Visual C++ 1.5 takes a big (3x) performance hit under all operating systems if you have less than 16 MB. I published an article about this (and other performance enhancements) in Windows/DOS Developer's Journal in May, 1995.

jimb@turningpoint.com, email, 7/11/95

How can I get Visual C++ 2.1? I can't find it in stores.

The point releases are part of the Visual C++ subscription. Only major releases are sold through retail, so you'll need to buy a subscription to get the point releases. Subscriptions are available from Microsoft, Programmer's Paradise, and Programmer's Shop.

Should I run under Windows 95 or NT?

Life is a bunch of trade-offs. The trade-offs here are if you run under Windows 95, you won't need as much memory, but the OS is not as robust as Windows NT, so you will probably crash more. On the flip side, if you run under Windows NT (a full 32-bit OS), you won't crash as much, but alas, you will need more memory. Personally, I prefer the Windows NT route. Windows NT caches all memory problems and handles them nicely for you without destabilizing the system.

Scot Wingo, scot@stingsoft.com, 6/18/95

How do I set the include/lib/exe directories?

Visual C++ versions earlier than 2.0 used environment variables INCLUDE/LIBDIR/EXEDIR. Visual C++ versions 2.0 or later use settings in the Visual C++ Tools menu. Select the Tools menu and then choose Options. A dialog box opens, and you then select the Directories tab. There you can set Include directories, Library directories, Executable directories, and so on.

Lee, Jin Woo, lee@sam1.info.samsung.co.kr, via programmer.win32, 6/10/95

I can't compile any programs! Help!

Question: I just installed Visual C++ 1.51 on my system. Installation proceeded smoothly without any errors. However, I can't compile any programs! Even when I try to compile the simplest and shortest programs, I get this error message:

Can't open the compilation response file

Answer: A common cause of this type of error is having a TMP or TEMP environment variable that isn't pointing at a valid directory. For example, your AUTOEXEC.BAT file says:

set TMP=C:\TMP

and you don't have a C:\TMP directory.

chris@chrism.demon.co.uk, programmer.misc, 6/18/95

Can I set up a project to search different paths for source?

I would like to have my projects first search for the source in a local directory, and if it can't find it there, search a network drive.

Joe Kinsella, jkinsella@procd.com

How do I build a browser file for all of MFC?

It's nice to be able to browse the MFC classes and source code. The best way to do this is via some Microsoft-supplied .BAT files for the Microsoft Software Library:

BLDBSC15.BAT—for Visual C++ 1.5

BLDBSC20.BAT—for Visual C++ 2.0

BLDBSC21.BAT—for Visual C++ 2.1

Basically, you want invoke the compiler on every file with /Zs as the option, which means generate the .sbr file and no .obj. Next, you want to run bscmake.exe on the generated .sbr files to create your .bsc file. The MFC makefile will complain about the missing .obj, but you can ignore that warning. It will take significantly longer and more time to create both .sbrs and .objs.

Scot Wingo, scot@stingsoft.com, 6/25/95

It is worth noting that Visual C++ 2.1 has a pre-built browser file that is on the CD-ROM but is not installed. It can be loaded at any time into the IDE with the File/Open command.

jimb@turningpoint.com, email, 7/11/95

If you are using the 32-bit versions, you can get more information in the README.TXT file in the \msvc20\mfc\src directory. It tells you to move to that directory and from the DOS prompt run:

nmake DEBUG=1 BROWSEONLY=1

billb@microsoft.com, mfc-l, 7/17/95

Language Feature Questions

Does Visual C++ support templates and exception handling?

The 32-bit Visual C++ 2.0 release introduced templates and exception handling. There is no support for these C++ features in 16-bit versions of the product.

It is worth noting that the 16-bit implementation of THROW and CATCH are brain-damaged. They do not clean up the stack as it unwinds.

jimb@turningpoint.com, email, 7/11/95

Does Visual C++ support the Standard Template Library?

Yes! See I'm having problems using MFC 4.0 and the STL. What could be wrong? for some hints. This support was added with version 4.0.

Does Visual C++ support RTTI?

Yes, version 4.0 does.

Scot Wingo, scot@stingsoft.com, 6/7/95

Religious Questions

Which is better—OWL or MFC, Borland C++ or Microsoft Visual C++?

This is constantly getting asked on Usenet. The answer really depends on what you are doing. If you demand the latest C++ features such as templates, RTTI, etc., Borland C++ usually has these first. But be careful, when Borland went from OWL 2 to 3 (or was it 1 to 2?) they made everybody completely rewrite their applications. Applications that were written with MFC version 1.0 still work with the newer versions of MFC today! The best advice is to get the features from each vendor and see what's best for your situation.

Scot Wingo, scot@stingsoft.com, comp.lang.c++, 6/8/95

Should I use Visual C++ or Visual Basic?

(Here's a funny analogy I saw posted...) Well, the principle is the same (create interface, add code to respond to events, add code to do something useful). But programming in Visual Basic is like riding a kiddy bike, while programming in C++ is like driving a Formula 1 racing car—be prepared for accidents.

But seriously—Visual Basic is interpreted, Visual C++ is compiled, therefore Visual C++ programs should be much faster (if written well). It's generally believed that Visual Basic is the best way to "prototype" a user-interface, but when it comes to code reuse and solving larger problems, Visual Basic breaks down. Visual C++ on the other hand is not as easy to use as Visual Basic, but once you learn it, you can write much more complex programs than with Visual Basic. The Readers Digest version of all this is: It depends on the application you are writing.

Scot Wingo, scot@stingsoft.com, 6/18/95

MFC philosophy (from a Microsoftie!)

Just a note about the classes provided in MFC.... Keep in mind that these classes are designed as "general-purpose" classes, not "all-purpose" classes. No one implementation can have performance characteristics that are ideal for all possible applications. It is up to you, the programmer, to evaluate a provided implementation and decide whether it is appropriate for the task at hand. If it is not, you have several alternatives: modify or subclass the provided implementation, find a more appropriate class from another source, or write one from scratch.

elsbree@msn.com, mfc-l, 7/15/95

Should I use the MFC collections or the STL collections?

Please contribute.

Advanced Visual C++ Tips and Tricks

How do I see the Visual C++ "Easter Eggs"?

FYI: Easter eggs are hidden screens that usually have secret initials, development team names, etc.

To see the spinning PLUS with the Visual C++ team members:

In Visual C++ 2.0 or 2.1:

  1. Bring up the About box: click Help, then click About.

  2. Press CTRL+TAB and double click in the middle of the box at the same time.

Note   You must have the Visual C++ CD-ROM loaded for this to work, I think.

If the procedure above does not work, try this:

  1. Copy the MSVCCRD.DLL from the CD-ROM to \msvc\bin.

  2. Press CTRL and double-click the picture in the dialog.

Note   Release the CTRL key at the same time as the second click.

Jeff O'Halloran, ohallorj@pwc-tpc.ca

To see the Visual C++ 4.0 About box, double-click in the About box while the CD-ROM is in the drive and you are holding the CTRL key down. The OK button should go away. Wait about 3–5 minutes and you should see a pretty neat flight simulator! You can browse the picture by opening msdevcrd.dll, which lives in \msdev\bin.

Scot Wingo, scot@stingsoft.com

What are the command-line options to Visual C++?

MSVC /V—Runs the compiler in a DOS box (version 1.5 only?)

mark@techop.demon.co.uk

MSVC /NOLOGO—Runs Visual C++ without the About box, saves a second or two.

MSVC /bppassc:yes—Enables a cool breakpoint counter in the "Breakpoints" dialog (under the Debug menu).

jimb@turningpoint.com, email, 7/11/95

MSVC -p—attaches Visual C++ to a process.

How to change the color of ClassWizard-generated code!

The default color for text modified by the ClassWizard is black print on a white background. Visual C++ is aware of the code that the ClassWizard modifies and can highlight these changes for you using a different color.

Highlighting the text ClassWizard modifies makes the new modifications very obvious and easy to find. To do this, from the Tools menu, choose Options. Then select the Format tab in the Options dialog box. From the Colors Listbox, select Wizard Code. Then define the colors for text and the background.

Note   Only applies to Visual C++ 2.x (and 4.x), but it's waaaay cool!

Visual C++ Knowledge Base article Q125779, 6/25/95

Ten cool things you can do in the Visual C++ editor!

CTRL+ALT+T shows your tab characters.

SHIFT+ESC closes the active dockable window.

CTRL+F3 finds the next occurrence of the current word.

CTRL+M finds the matching bracket.

CTRL+> and CTRL+< find the next/prev matching #ifdef/#else/#endif.

CTRL+SHIFT+R starts/stops macro recording.

CTRL+SHIFT+P plays recorded macro.

Right-click #includes to open the header file.

TAB/SHIFT+TAB indent or unindent selected lines.

Hold the ALT key down to select columns.

Jeff Henshaw, borrowed off MFC PDC slide, 6/25/95

Note   Not all of these work in Visual C++ 1.5x; most do in 2.x and 4.x.

How do I speed up Visual C++ compiles?

Use precompiled headers, turn off the browser (Options:Project:Compiler:Listing Files:Browser Information), increase and/or decrease the size of your disk cache, tinker with the INCLUDE and LIB environment variable directory orders. That's about it.

ebarb@iadfw.net, programmer.tools, 8/19/95

Make all MFC keywords a different color!

Download (ftp://landru.unx.com/pub/mfc_faq/archive) the file USERTYPE.DAT from the FAQ Archive. This archive contains MFC samples that illustrate FAQs. Try it, you'll like it!

Note   This has been updated for version 4.0.

Scot Wingo, scot@stingsoft.com, 8/31/95

An easy way to launch 4.x projects without .mdp files.

zFor very large projects you might not bank or put .mdp files into the version control system. You just want to grab the makefile and go. The problem is that Visual C++ does not easily recognize .mak files. Here's an easy way to launch right from a makefile to Visual C++ 4.0 and have a .mdp file created.

  1. Bring up the registry edit (Registry.exe for Windows 95 and Regedt32.exe for Windows NT 3.51).

  2. Activate the HKEY_CLASSES_ROOT window.

  3. Add a new key:

    .mak

  4. Add a new string value:

    mdpfile

  5. Close the registry.

That's it. Now you can just select any Visual C++ 4.0 makefile from File Manager or Explorer and the Visual C++ IDE will come up and a project workspace (.mdp) will be created for that makefile. You no longer have to go into the visual environment do a "file open", enter a filename, and select "open as...makefile". This is definitely a time-saver.

G_LEDONNE@msn.com

Miscellaneous Visual C++ Questions

What are all these files that Visual C++ is creating?

Here's a table that explains the common extensions and what Visual C++ uses them for:

Extension Use Notes
.APS AppStudio file
.BSC Browser file .SBRs combined into 1 .BSC.
.CLW ClassWizard file
.ILK Incremental linker file
.NCB Contains the ClassView information Added in 4.0; delete if you have problems.
.PCH Pre-compiled header file
.PDB Debugging info /Z7 affects this.
.RES RC "object" file Linked into .EXE.
.SBR Browser info for 1 file Combined into .BSC.
.VCP Visual C++ state file

How do I change from using MFCXX.DLL to using a statically linked library?

You need to flick a few settings in the build settings windows:

In the C/C++ tab, select the General Category. Remove "_AFXDLL" from the list of preprocessor definitions. In the Code Generation tab, select Multithreaded or Debug Multithreaded, whichever is appropriate for your build.

In the Resources tab, make sure that "_AFXDLL" doesn't appear in the list that's in the Preprocessor Definitions edit.

 blaszczak@BIX.com

How do I report a bug to Microsoft?

If you find what you think is a bug, here's what you should do:

  1. Panic.

  2. Threaten to nuke my neighborhood.

  3. Try to consolidate the problem.

  4. Take that consolidation to another project on another machine and try it.

  5. If it still is a problem, step through the code. Think.

  6. Think some more.

If you're still sure it's a bug, do one or more of these things:

But realize that calling PSS is the official, guaranteed way to get help.

My job is to write software, and I try to be pretty good at that. (I'm pretty good at going to hockey games, too.) But I really can't also do the job of product support on a full-time, full-responsibility basis. Sending bug reports directly to me will do nothing more than make me feel awkward and say "Sorry, can't help" to you.

Thanks for understanding,

mikeblas@iqnterserv.com

Visual C++/MFC 4.0 Specific Hints, Problems, etc.

Why aren't my windows being created in MFC 4.0?

The problem is probably that you are relying on one of the MFC 3.x and earlier registered window classes for the class name passed to your ::Create(). For example, a very popular way to create a window with a white background is to use "AfxViewOrFrame". In MFC 4.0, not only have all of the window class names been changed, but they also happen dynamically when needed!

The solution is to use AfxRegisterWndClass() and pass the results to Create(). Be sure to specify the right flags to get the desired results. Also check out MFC Technical Note 1, which has been revised for 4.0.

Scot Wingo, scot@stingsoft.com, 1/20/96

How do I convert a Visual C++ 2.x makefile over to 4.x?

  1. Select File/Open.

  2. Select your *.mak file.

  3. Select Open as: Makefile.

  4. Select Open, then Visual C++ will offer you to convert it to a Visual C++ workspace—this is what you want.

ClassWizard has problems wiring controls to members in international 4.0 versions—what the heck do I do?

To test to see if you have the problem:

  1. In Visual C++ version 4.0, use the AppWizard to create a dialog-based application.

  2. Then use the dialog Resource Editor to add controls, etc., onto the dialog box generated above.

  3. Then fire up the ClassWizard to associate member variables to the added controls. The control IDs are not listed in the command ID windows (the IDCANCEL and IDOK are there and that's it!) of the member variables property page.

The control IDs are in the messagemap property page but not on the member variables property page! Huh?

The fix:

The fix is to change the language property of the dialog template (highlight the name of the dialog box in the resource window and click right mouse button). For me, I had to change the language property from English (US) to English (Australian)—only after doing this do the member variables of controls appear. I assume this property must match your Windows 95 chosen language; in any case the change fixed it for me and a German user who had the same problem.

doug@psy.uwa.edu.au, email, 12/13/95

Visual C++ 4.0 crashes all the time on me! Help!

I haven't personally experienced these problems, but here are some solutions (some are probably old wives’ tales) for solving the problems:

Make sure you have downloaded the service update from: http://www.microsoft.com/visualc.

If you're using subprojects, this is probably the culprit—they're very unstable.

If you're using 200+ files, try to carve your project into DLLs.

Try removing the .ncb file—this is where the ClassView info is stored.

If you converted your project over from 2.x and are having problems, start fresh with a 4.0 project and insert your files into it.

How do I add components (not just classes) to the Component Gallery?

The APIs used for the Component Gallery have not been made public yet by Microsoft.

What is up with the Visual C++ 5.0 help system?

It is widely known (at least to everyone I talk to) that the Visual C++ 5.0 help system is very slow! Microsoft replaced the wonderful, speedy RTF-based WinHelp viewer system with an HTML-based Internet Explorer viewer system. Why is it slow? Well, now it is as if you are using Alta Vista to search because the help files are in HTML. There is an indexing system that is suppose to get better, but it is really slow right now.

Here's what I do. . .

  1. Remove all of the help files.

  2. Install Visual C++ 4.2, choose only the IDE and help file options. Install into some unique directory such as c:\vc42_help.

  3. Now use Visual C++ 4.2 for help and Visual C++ 5.0 for compiles.

Sounds cheesy and it is, but the 5.0 help is really that slow if you are a heavy user like I am (I'm not sure if that is a good or bad thing).

Scot Wingo, scot@stingsoft.com

MSDN Editor's Note   Yes, the initial release of InfoViewer version 5.0 (the Internet Explorer–based browser for the MSDN Library and various documentation sets) was very slow. A "performance-enhanced" version has been included with the MSDN Library since the April 1997 release and will be included with Visual Studio 97 and Visual C++ 5.0 by early summer of 1997.

If you are considering using the Visual C++ 4.2 documentation with Visual C++ 5.0, beware that there are significant differences between versions 4.2 and 5.0—the version 4.2 help will not be as accurate as the version 5.0 help. MSDN suggests using the Visual C++ 5.0 documentation with Visual C++ 5.0.