Activating the First Instance with the Command Line

Date: 01 April 1997
Author: Rich Goldstein, MD

This method will allow a second instance of an application which is activated by the shell pass the command line to the previously running instance, and bring it to the top as well. This method suffers from the same limitation as the 16-bit code in Letting Only One Instance Run, but since this method works in both 16- and 32- bit modes, the mutex method can be used where appropriate.

The key to this method is the use window properties and Global Atoms. Additionally, a registered window message is used to help pass information from one application to the other.

First, in the application class, define a string that is likely to be unique, and not used by yourself or anyone else as a unique application identifier.

const char *szUniqueAppString = "TestOneInstance";
UINT WM_MY_ACTIVATEAPP = 
0;

Then, in the applications main window (the frame window), add a property to the window:

      void TMyMainWindow::SetupWindow()
      {
         TDecoratedMDIFrame::SetupWindow();
         
// Add our unique property
         ::SetProp(GetHandle(), szUniqueAppString, (HANDLE)
1);   // value must not be zero
      }

The currently running instance is identified by the presence of this property on the main window. The OwlMain function will search for this property before running the TApplication derived class. If an appropriate window is found, the command line is saved in a global atom, whose handle is passed via the registered message to the currently running instance.

int OwlMain (int , char* argv[])
{
   TTestApp app;

   WM_MY_ACTIVATEAPP = ::RegisterWindowMessage(szUniqueAppString);

   HWND desktop = ::GetDesktopWindow();
   HWND child= ::GetWindow(desktop, GW_CHILD);

   
while (child)
   {
      
if (::GetProp(child, szUniqueAppString))
      {
         
// found a window with the property
         
// store the current command line as an atom...
         ATOM atom = GlobalAddAtom(app.GetCmdLine().c_str());
         
// send the message to the currently running app
         ::SendMessage(child, WM_MY_ACTIVATEAPP, atom, 
0);
         
// don't let this instance continue now
         
return 0;
      }
      child = ::GetWindow(child, GW_HWNDNEXT);
   }
   
// No prior instance found, so proceed.
   
return app.Run();
}

All that remains is for the main window to recognize the message, and process the command line:

DEFINE_RESPONSE_TABLE1(TMyMainWindow, TDecoratedMDIFrame)
   EV_REGISTERED(szUniqueAppString, EvNewInstance),
END_RESPONSE_TABLE;


LRESULT TMyMainWindow::EvNewInstance(WPARAM atom, LPARAM)
{
   
char buff[256];

   
if (::GlobalGetAtomName(atom, buff, 256))
   {
      
// free up the atom space
      ::GlobalDeleteAtom(atom);
      
// Process the command line!
      TMDIClient* client = GetClientWindow();
      
if (client)
      {
         
if (::IsIconic(GetHandle()))
            ::SendMessage(GetHandle(), WM_SYSCOMMAND, SC_RESTORE, 
0); 
         
#ifdef __WIN32__
         ::SetForegroundWindow(GetHandle());
         
#else
         ::BringWindowToTop(GetHandle());
         
#endif
         TMDIChild* child = 
new TMDIChild(*client, buff);
         child->Create();
         ::PostMessage(client->GetHandle(), WM_MDIACTIVATE, (WPARAM)child->GetHandle(), 
0);
      }
   }
   
return 0;
}

You can see the entire source here.