13.2.  Application Specific Questions

Microsoft Visual C++/Microsoft Foundation Classes


13.2.  Application Specific Questions

13.2.1. 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, choose Advanced..., and then select 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();

MSVC Knowledge Base, 6/4/95

13.2.2. How do I limit my MFC application to one instance?

Look at the Microsoft sample ONETIME.EXE, (MSDN CD or ftp.microsoft.com). 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 popups?
        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 popups, 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;
    //...
}

Niels Ull Jacobsen ([email protected]), programmer.tools, 6/19/95

See also MS Knowledge base article Q124134 ( "Allowing Only One Application Instance on Win32s") and Advanced Windows NT , chapter 7, "Prohibiting Multiple Instances of an Application from Running: The MultInst Sample Application" (available on the MSDN).

Niels Ull Jacobsen ([email protected]), email, 8/8/95

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

[email protected]

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

Step1:
=======
In your main file, add:

#pragma data_seg(".SharedData")
LONG nUsageCount = -1;
#pragma data_seg()
 
Step 2 :
=======
In your Application's InitInstance(), call:
InterlockedIncrement ( &nUsageCount );
 
This function returns the incremented value of the variable. If it is non-zero, you know that you are not the first App.
In your Application's ExitInstance() call:
InterlockedDecrement( &nUsageCount );
 
Step3:
=======
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

[email protected]

You'd better use one of the built-in synchronization methods. See 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 it's window or CreateFileMapping will eventually succeed. The advantage of using CreateFileMapping instead of CreateObject is that it also works on Win32s.

- [email protected]

Note: There's a sample of this that was contributed by [email protected] (John Xu) called onetime4.zip that is in the MFC FAQ archive (see section 2.2.6 for MFC FAQ archive details).

13.2.3. 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, [email protected], 6/23/95, programmer.win32

13.2.4. 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().

MS FAQ, 6/25/95