Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Preventing multiple instances of application

Status
Not open for further replies.

danielmashman

Programmer
Sep 12, 2011
4
0
0
NZ
I am trying to implement a Delphi example I found for preventing multiple instances of an application built in c++ builder.

I have created a unit called CheckPrevious.cpp with a routine called RestoreIfRunning() and a destructor. How do I use this unit from the main project source file within WinMain()? To use the units for the forms you use the keyword USEFORM(Unit1.cpp, Form1). I know there is a USEUNIT keyword but I cannot figure out if this is what I need to use. Or do I simply include the header file CheckPrevious.h and then create an instance of the CheckPrevious class within WinMain()?

Here is the code I have created within CheckPrevious.cpp:
Code:
CheckPrevious::~CheckPrevious(void)
{
	if(RemoveMe)
	{
		MappingHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, PChar(MappingName));
		if(MappingHandle != 0)
		{
			InstanceInfo = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TInstanceInfo));

			InstanceInfo.RunCOunter--;
		}
		else
			RaiseLastOSError();
	}
	if(Assigned(InstanceInfo))
		UnmapViewOfFile(InstanceInfo);
	if(MappingHandle != 0)
		CloseHandle(MappingHandle);
}


bool CheckPrevious::RestoreIfRunning(const THandle AppHandle, int MaxInstances)
{
	THandle MappingHandle;
	PinstanceInfo InstanceInfo;
	AnsiString MappingName;

	RemoveMe = true;

	MappingName = StringReplace(ParamStr(0), "\", "", TReplaceFlags() << rfReplaceAll);

	MappingHandle = CreateFileMapping(0xFFFFFFFF, nil, PAGE_READWRITE, 0, sizeof(TInstanceInfo), PChar(MappingName));

	if(MappingHandle = 0)
		RaiseLastOSError();
	else
	{
		if(GetLastError() != ERROR_ALREADY_EXISTS)	//Application not already running
		{
			InstanceInfo = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TInstanceInfo));
			InstanceInfo.PreviousHandle = AppHandle;
			InstanceInfo.RunCounter = 1;

			return true;
		}
		else	//application already running
		{
			MappingHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, PChar(MappingName));

			if(MappingHandle != 0)
			{
				InstanceInfo = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TInstanceInfo));

				if(InstanceInfo.RunCounter >= MaxInstances)
				{
					RemoveMe = false;

					if(IsIconic(InstanceInfo.PreviousHandle))
						ShowWindow(InstanceInfo.PreviousHandle, SW_RESTORE);

					SetForegroundWindow(Instance.PreviousHandle);
				}
				else
				{
					InstanceInfo.PreviousHandle = AppHandle;
					InstanceInfo.RunCounter++;

					return false;
				}
			}
		}
	}
}
 
I'm not familiar with the method you are using but my gut reaction would be to call the header file and then create an instance of the class.

I've used MUTEXes with success if you are interested in how to do that. It's very easy.



James P. Cottingham
[sup]I'm number 1,229!
I'm number 1,229![/sup]
 
Thanks. As I said this method is from a Delphi example I found that I am attempting to convert to C++. The main thing I want to achieve is to only allow one instance of the program to run and if it is already running restore the main form and bring to the front.

Currently my application is associated with a file type so that if the user double clicks on a file it will launch the application and the application will load the file. This is done with the following code in the constructor of the main form:
Code:
if(ParamCount() >= 1)
	{
        if ((AnsiPos(".MBD", ParamStr(1)) || AnsiPos(".mbd", ParamStr(1))))
	        LoadFile(ParamStr(1));
	}

Idearly if a file of this type is double clicked while an instance of the application is already running then the file would be loaded in the current instance.

It would be much appreciated if you could post some example code of using MUTEXes to prevent multiple instances so I could attempt this method.
 
OK. Here is an example from a program I called Clipping Line Measurer, aka CLiMer. In this example, it not only looks for the mutex named CLMmtx, it also checks to see if the correct keys are set up in the registry.

Code:
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    HANDLE CLMmtx; // Add handle for mutex
    try
    {
        // ***** Add section between stars (below)
        // Only one instance of this program can be run
        CLMmtx = OpenMutex (MUTEX_ALL_ACCESS, false, "CLiMer");
        if (CLMmtx == NULL)
            CLMmtx = CreateMutex (NULL, true, "CLiMer");
        else
        {
            ShowMessage("CLiMer is already running!");
            return 0;
        }

        // Check to see if registry is set up for CLiMer
        bool KeyIsThere = true;
        TRegistry* rCheck = new TRegistry;
        try
        {
           rCheck->RootKey = HKEY_LOCAL_MACHINE;
           KeyIsThere = rCheck->KeyExists("\\Software\\IVCUSA\\CLiMer");
        }
        __finally
        {
            delete rCheck;
        };

        if (!KeyIsThere)
        {
            Application->MessageBox("Registry is not correctly set up.\nRun CLiMer Setup Program!", "Registry Error", MB_OK);
            return 0;
        }
        // *** Add section between stars (above)

         Application->Initialize();
         Application->Title = "Clipping Line Measureer";
         // Data Module MUST be created first
         Application->CreateForm(__classid(TCLiMerDataModule), &CLiMerDataModule);
         Application->CreateForm(__classid(TCLiMerMainForm), &CLiMerMainForm);
         Application->Run();
    }
    catch (Exception &exception)
    {
         Application->ShowException(&exception);
    }
    catch (...)
    {
         try
         {
             throw Exception("");
         }
         catch (Exception &exception)
         {
             Application->ShowException(&exception);
         }
    }

    ReleaseMutex(CLMmtx); // Clear handle, too
    return 0;
}
//---------------------------------------------------------------------------

You create a handle at the beginning and release the handle at the end of the WinMain. In the try...finally statement, you open the mutex. If the mutex does not exist, you create the mutex and run your program. If the mutex does exist, then the program is already running and you can do something like show a warning (like I do),or you can make your program active, or . . .
I have not tried this method using the newer compilers or Windows 7.



James P. Cottingham
[sup]I'm number 1,229!
I'm number 1,229![/sup]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top