App Restart Procedure and potential anotherInstanceStarted() bug?


#1

Hi,

I'm trying implement a restart procedure that would happen after an update of our application. 

I was following the discussion here: http://www.juce.com/forum/topic/application-restart

modify your code so that you allow a second instance IF there is a specific command line option, and the second instance tells the previous instance to exit.

seems like a neat solution. 

However I'm having an issue where anotherInstanceStarted() isn't being called as expected. 

* I'm running JUCE v3.0.1

* Created a new basic window app from the Introjucer

* Set moreThanOneInstanceAllowed() to return true

* Added a logging statement to anotherInstanceStarted() in Main.cpp:

    void anotherInstanceStarted (const String& commandLine)

    {

        DBG("Another Instance Started: " << commandLine);

    }

* Run the application from Xcode (Debug configuration)

* From the project directory run another instance of the app in the command line:

$ ./Builds/MacOSX/build/Debug/Restart_Test_GUI_2.app/Contents/MacOS/Restart_Test_GUI_2

From the documentation I would expect anotherInstanceStarted() to be called in the first instance I opened. However I don't get any callbacks in either app. Changing moreThanOneInstanceAllowed() to return false quits the second instance on launch as expected but it still doesn't give me a callback. 

----------------

From digging around in JuceApplicationBase it looks like if moreThanOneInstanceAllowed() is true then the  sendCommandLineToPreexistingInstance() method is never executed, and therefore never instantiates the MultipleInstanceHandler and registers it as a ActionBroadcastListener for the callback.  
 

    if ((! moreThanOneInstanceAllowed()) && sendCommandLineToPreexistingInstance())

    {

        DBG ("Another instance is running - quitting...");

        return false;

    }

-----

Am I missing something fundamental to get this to work? Or is this a potential bug in JUCE?

Is there an easier solution for an update procedure? My general aim was as follows:

* Replace the old binary with the new one

* Run a script to launch a new instance of the application (with some command line params)

* Upon launch the initial instance detects it's an update and shuts itself down

 

Thanks in advance,

Joe


#2

Following up on this, I still haven't managed achieve the desired functionality but I found some things that threw me off initially that might be worth looking into. 

 

File::getSpecialLocation (File::currentExecutableFile) returns a relational instead of an absolute path (on OSX anyway). 

This means that:

 

static NSString* getBroacastEventName()
{
    return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation
            (File::currentExecutableFile).hashCode64()));
}

Will return a different broadcast ID if you run the app from Xcode or run it from the command line with a relational path:

i.e:

$ ./PATH/TO/APP

And thus will not receive the callback for another instance started.

---

sendCommandLineToPreexistingInstance() (juce_ApplicationBase.cpp Line 248) will never get called if the app allows multiple instances. As far as I can see this should definitely be called if you allow multiple instances, but maybe I'm missing something?

If I change the code to the following I get the callback correctly when running the app from the command line (although annoyingly not yet in Xcode). 

#if JUCE_HANDLE_MULTIPLE_INSTANCES

bool sendCommandLineResult = sendCommandLineToPreexistingInstance();

if ((! moreThanOneInstanceAllowed()) && sendCommandLineResult)

{

    DBG ("Another instance is running - quitting...");

    return false;

}

#endif

 

Any ideas more than welcome! Is anyone else restarting their app a different way?

Thanks,
Joe


#3

If I change the code to the following I get the callback correctly when running the app from the command line (although annoyingly not yet in Xcode). 

Actually that's not true, I do get the anotherInstanceStarted() once the focus has shifted back to the Xcode-ran app. 


#4

OK so I got this working, albeitly in a different manner.  I scratched all my previous code as it required some changes to JuceApplicationBase that I felt uncomfortable with and there were still inconsistencies when running it from Xcode and from the command line. 

In the end I added a shell script to the project:

#!/bin/bash -e
sleep 1
open $1
exit 0

And added the following code to relaunch:

void SomeClass::restart() 
{
    String applicationPath = File::getSpecialLocation(File::currentApplicationFile).getFullPathName();
    String scriptPath = applicationPath  + "/Contents/Resources/relaunch.sh";
    String relaunchCommand = scriptPath + " " + applicationPath;
    ScopedPointer<ChildProcess> scriptProcess = new ChildProcess();
    scriptProcess->start(relaunchCommand, (!ChildProcess::wantStdErr | !ChildProcess::wantStdOut));
    JUCEApplication::getInstance()->quit();
}

Much less headache and I don't know I didn't try this in the first place! Admittedly it's OSX only at the moment.

Cheers,

Joe

 


#5

Hello, I'm also not seeing anotherInstanceStarted being called. I tried just adding a breakpoint to the callback on a fresh GUI project application and nothing happens when I run multiple instances of the app. Seems like there are a couple threads about this already so I apologize if I'm beating a dead horse but, it's not working on the default introjucer project. Any ideas?