SAMPLE: Limiting 32-bit Applications to a Single Instance

Last reviewed: July 31, 1997
Article ID: Q141752
The information in this article applies to:
  • The Microsoft Foundation Classes(MFC) included with: - Microsoft Visual C++, 32-bit Edition, versions 4.0, 5.0

This is the 32-bit version of this sample.

SUMMARY

The ONET32 sample application demonstrates how to limit a Microsoft Foundation Class Library (MFC) application to a single instance.

ONET32.EXE is a self-extracting file and should be executed as follows:

  ONET32 -d

The '-d' option maintains the subdirectory structure. The following file is available for download from the Microsoft Software Library:

 ~ Onet32.exe (size: 41396 bytes) 

For more information about downloading files from the Microsoft Software Library, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q119591
   TITLE     : How to Obtain Microsoft Support Files from Online Services

MORE INFORMATION

There are several ways to limit a Windows-based application to a single instance. This sample program uses a technique in which a custom window class is registered for the application's main frame window. In subsequent instances, CWinApp::InitInstance() searches for this window class and then activates the prior instance.

This technique was chosen is fairly easy to implement.

The following code fragments show the essential requirements of this technique:

  1. Override CWinApp::InitInstance() to check for, and activate, any previous instance of the application. Also, register the our own window class as follows:

          // Add a static BOOL that indicates whether the class was
          // registered so that we can unregister it in ExitInstance
          static BOOL bClassRegistered = FALSE;
    

          BOOL COneT32App::InitInstance()
          {
    
              // If a previous instance of the application is already running,
              // then activate it and return FALSE from InitInstance to
              // end the execution of this instance.
    
              if(!FirstInstance())
                return FALSE;
    
              // Register our unique class name that we wish to use
              WNDCLASS wndcls;
    
              memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL
                                                      // defaults
    
              wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
              wndcls.lpfnWndProc = ::DefWindowProc;
              wndcls.hInstance = AfxGetInstanceHandle();
              wndcls.hIcon = LoadIcon(IDR_MAINFRAME); // or load a different
                                                      // icon
              wndcls.hCursor = LoadCursor( IDC_ARROW );
              wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
              wndcls.lpszMenuName = NULL;
    
              // Specify our own class name for using FindWindow later
              wndcls.lpszClassName = _T("MyNewClass");
    
              // Register new class and exit if it fails
              if(!AfxRegisterClass(&wndcls))
              {
                TRACE("Class Registration Failed\n");
                return FALSE;
              }
              bClassRegistered = TRUE;
    
              // Rest of InitInstance goes here
              ...
              ...
              ...
          }
    
    

  2. Add a member function to your CWinApp-derived class that actually does the work of checking for, and activating of, a previous instance:

          BOOL COneT32App::FirstInstance()
          {
    
            CWnd *pWndPrev, *pWndChild;
    
            // Determine if another window with our class name exists...
            if (pWndPrev = CWnd::FindWindow(_T("MyNewClass"),NULL))
            {
              // if so, does it have any popups?
              pWndChild = pWndPrev->GetLastActivePopup();
    
              // If iconic, restore the main window
              if (pWndPrev->IsIconic())
                 pWndPrev->ShowWindow(SW_RESTORE);
    
              // Bring the main window or its popup to
              // the foreground
              pWndChild->SetForegroundWindow();
    
              // and we are done activating the previous one.
              return FALSE;
            }
            // First instance. Proceed as normal.
            else
              return TRUE;
          }
    
    

  3. Override CWinApp::ExitInstance() to unregister the class if it was registered as follows:

          int COneT32App::ExitInstance()
          {
    
            if(bClassRegistered)
              ::UnregisterClass(_T("MyNewClass"),AfxGetInstanceHandle());
            return CWinApp::ExitInstance();
          }
    
    

  4. Override CFrameWnd::PreCreateWindow() to use your window class instead of the one registered automatically by MFC as follows:

          BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
          {
    
              // Use the specific class name we established earlier
              cs.lpszClass = _T("MyNewClass");
    
              // Change the following line to call
              // CFrameWnd::PreCreateWindow(cs) if this is an SDI application.
              return CMDIFrameWnd::PreCreateWindow(cs);
          }
    
    

REFERENCES

MFC Technical Note #1 discusses window class registration.

The Following Knowledge Base article discusses how to register MFC window classes:

   ARTICLE-ID: Q140596
   TITLE     : MFC 4.0 No Longer Pre-Registers Window Classes


Additional query words: ONETIME
Keywords : MfcUI kbfile kbprg kbsample kbfile
Technology : kbMfc
Version : 4.0 5.0
Platform : NT WINDOWS
Solution Type : kbcode


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 31, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.