Command line args if launched from terminal

Mac OSX specific forum
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Command line args if launched from terminal

Post by coder14 »

MacOS does not launch multiple instances of the same app by default. If an associated file is double-clicked in Finder when an instance of the app is already running we can get the file name with this callback routine from Fred:

http://forums.purebasic.com/english/vie ... 0d#p391284

But if a second instance is started from Terminal with the "open -a" command with "--args" Fred's routine does not get the parameters and the second instance will be shut down (unless the "open -n" flag is used). Is there any way to get the parameters if the app is launched from Terminal?
Wolfram
Enthusiast
Enthusiast
Posts: 568
Joined: Thu May 30, 2013 4:39 pm

Re: Command line args if launched from terminal

Post by Wolfram »

Maybe you can do it like this:

Code: Select all


Global Window_0, Button_0


Procedure isAlreadyRunning()
  
  thisApp =CocoaMessage(0,0, "NSRunningApplication currentApplication")
  thisAppName =CocoaMessage(0, thisApp, "localizedName")

  If thisAppName
    thisName.s =PeekS(CocoaMessage(0, thisAppName, "UTF8String"), -1, #PB_UTF8)
  EndIf
  
  NSArray_apps = CocoaMessage(0,CocoaMessage(0,0,"NSWorkspace sharedWorkspace"),"runningApplications")
  If NSArray_apps
    count = CocoaMessage(0, NSArray_apps, "count")

    For i = 0 To count -1
      app =CocoaMessage(0, NSArray_apps, "objectAtIndex:",i)
      If app

        appName = CocoaMessage(0, app, "localizedName")

        If appName
          Name.s =PeekS(CocoaMessage(0, appName, "UTF8String"), -1, #PB_UTF8)
          
          If Name =thisName
            result +1
          EndIf
          
        EndIf
      EndIf
      
    Next
  EndIf
  
ProcedureReturn result -1
EndProcedure


Procedure OpenWindow_0(x = 0, y = 0, width = 450, height = 160)
  Window_0 = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  Button_0 = ButtonGadget(#PB_Any, 160, 50, 130, 25, "quit")
  
  
  
  
EndProcedure


Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
	Case #PB_Menu_Quit
          ProcedureReturn #False
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_0
          ProcedureReturn #False
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

If isAlreadyRunning() 
  MessageRequester("Message", "App is already running")
  
Else
  
  OpenWindow_0()
  
  Repeat
    event = WaitWindowEvent()
  Until Window_0_Events(event) = #False
  
EndIf
macOS Catalina 10.15.7
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Command line args if launched from terminal

Post by coder14 »

Wolfram wrote:Maybe you can do it like this:

Code: Select all


Global Window_0, Button_0


Procedure isAlreadyRunning()
  
  thisApp =CocoaMessage(0,0, "NSRunningApplication currentApplication")
  thisAppName =CocoaMessage(0, thisApp, "localizedName")

  If thisAppName
    thisName.s =PeekS(CocoaMessage(0, thisAppName, "UTF8String"), -1, #PB_UTF8)
  EndIf
  
  NSArray_apps = CocoaMessage(0,CocoaMessage(0,0,"NSWorkspace sharedWorkspace"),"runningApplications")
  If NSArray_apps
    count = CocoaMessage(0, NSArray_apps, "count")

    For i = 0 To count -1
      app =CocoaMessage(0, NSArray_apps, "objectAtIndex:",i)
      If app

        appName = CocoaMessage(0, app, "localizedName")

        If appName
          Name.s =PeekS(CocoaMessage(0, appName, "UTF8String"), -1, #PB_UTF8)
          
          If Name =thisName
            result +1
          EndIf
          
        EndIf
      EndIf
      
    Next
  EndIf
  
ProcedureReturn result -1
EndProcedure


Procedure OpenWindow_0(x = 0, y = 0, width = 450, height = 160)
  Window_0 = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  Button_0 = ButtonGadget(#PB_Any, 160, 50, 130, 25, "quit")
  
  
  
  
EndProcedure


Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
	Case #PB_Menu_Quit
          ProcedureReturn #False
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_0
          ProcedureReturn #False
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

If isAlreadyRunning() 
  MessageRequester("Message", "App is already running")
  
Else
  
  OpenWindow_0()
  
  Repeat
    event = WaitWindowEvent()
  Until Window_0_Events(event) = #False
  
EndIf
Thanks Wolfram. But I am already doing a file mutex to determine if the application is already running.

What I need is to get the command parameters from instances attempting to launch from Terminal but keep getting shut down because MacOS allows only a single instance by default.

How would I get the command line arguments when a second instance is being launched with arguments but gets shut down by MacOS?
Wolfram
Enthusiast
Enthusiast
Posts: 568
Joined: Thu May 30, 2013 4:39 pm

Re: Command line args if launched from terminal

Post by Wolfram »

MacOS allows only a single instance by default.
This is not 100% true, because if you run this inside a new terminal window you will get a new program running.

Code: Select all

/Applications/TextEdit.app/Contents/MacOS/TextEdit
Only if you run the .app packet OSX will not open a second version of it.
macOS Catalina 10.15.7
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Command line args if launched from terminal

Post by coder14 »

Wolfram wrote:
MacOS allows only a single instance by default.
This is not 100% true, because if you run this inside a new terminal window you will get a new program running.

Code: Select all

/Applications/TextEdit.app/Contents/MacOS/TextEdit
Only if you run the .app packet OSX will not open a second version of it.
But how do we get the command line parameters if the app is started in Terminal with "open -a" options? The app does not open a new instance but the command line parameters are lost.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Command line args if launched from terminal

Post by wilbert »

I think you should use the normal PureBasic CountProgramParameters() and ProgramParameter() commands for that.
Windows (x64)
Raspberry Pi OS (Arm64)
Wolfram
Enthusiast
Enthusiast
Posts: 568
Joined: Thu May 30, 2013 4:39 pm

Re: Command line args if launched from terminal

Post by Wolfram »

But how do we get the command line parameters if the app is started in Terminal with "open -a" options? The app does not open a new instance but the command line parameters are lost.

Code: Select all

;read command line parameters
If CountProgramParameters()

    While argCount <= CountProgramParameters()
    argValue.s = ProgramParameter(argCount)
    If Left(argValue, 1) = "-" And Len(argValue) > 1
      argValue = LCase( Right(argValue, Len(argValue) -1) )
      Select argValue
        Case "p"
          ;Do something
          
        Default
          PrintN ("read "+argValue)
      EndSelect
    EndIf
    
   argCount +1
  Wend

EndIf
macOS Catalina 10.15.7
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Command line args if launched from terminal

Post by coder14 »

Thank you for your answers. CountProgramParameters and ProgramParameter works in the first instance. But how do i get the parameters from the second instance.

Starting my app from Terminal:
1. I launch my app (from Terminal or Finder doesn't matter). While this instance is running:
2. I launch another instance of my app from Terminal like this:

Code: Select all

open -a myApp.app --args params
The second instance is able to get the "params" with CountProgramParameters and ProgramParameter. How is it going to pass the "params" to the first instance?


The same scenario from Finder works differently:
1. I launch my app (from Terminal or Finder doesn't matter). While this instance is running:
2. I launch another instance of my app from Finder (by double-clicking an associated file or dragging an associated file onto the myApp.app icon in Finder).
3. Using the PB_Gadget_SetOpenFinderFiles(Callback) function I am able to get the name of the file that launched the app.

Is there a way or are the parameters lost forever?
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Command line args if launched from terminal

Post by wilbert »

coder14 wrote:Is there a way or are the parameters lost forever?
I'm confused right now about what you want.

Do you mean that if you use

Code: Select all

open -a myApp.app --args params
you want the arguments to be passed to the instance that is already running ?
Windows (x64)
Raspberry Pi OS (Arm64)
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Command line args if launched from terminal

Post by coder14 »

wilbert wrote:
coder14 wrote:Is there a way or are the parameters lost forever?
I'm confused right now about what you want.

Do you mean that if you use

Code: Select all

open -a myApp.app --args params
you want the arguments to be passed to the instance that is already running ?
Yes! :D
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Command line args if launched from terminal

Post by wilbert »

:? I searched a bit on the internet but so far I haven't found a solution.

You can of course open a new instance with -n but that probably isn't what you want.

Code: Select all

open -n -a myApp.app --args params
Edit:
Sorry, I overlooked in your first post that you already knew about -n
Last edited by wilbert on Mon Mar 06, 2017 2:57 pm, edited 1 time in total.
Windows (x64)
Raspberry Pi OS (Arm64)
Wolfram
Enthusiast
Enthusiast
Posts: 568
Joined: Thu May 30, 2013 4:39 pm

Re: Command line args if launched from terminal

Post by Wolfram »

Can you give us a function description of what do you exactly want?

Do you want that all instances do the same or different things?
macOS Catalina 10.15.7
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Command line args if launched from terminal

Post by coder14 »

Wolfram wrote:Can you give us a function description of what do you exactly want?

Do you want that all instances do the same or different things?
By default Mac does not allow multiple instances of an app to run concurrently. If an instance is already running, trying to launch it again using the command-line "open -a myapp.app --args NEWPARAMS" from Terminal will not work. How do I get NEWPARAMS from the instance that is being shut down?
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Command line args if launched from terminal

Post by wilbert »

I don't know if it is even possible what you want.

Did you consider alternative options like using AppleScript to tell to your already running application what you want it to do ?
From the terminal you would need to use osascript if you would do it this way. Like

Code: Select all

osascript -e 'tell app "Finder" to make new Finder window'
This topic from deseven explains how to make your application respond to AppleScript if you are interested http://www.purebasic.fr/english/viewtop ... 19&t=66750
Windows (x64)
Raspberry Pi OS (Arm64)
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Command line args if launched from terminal

Post by coder14 »

wilbert wrote:I don't know if it is even possible what you want.

Did you consider alternative options like using AppleScript to tell to your already running application what you want it to do ?
The running instance would not even know that a second instance is being launched. But when the second instance is shut down we will lose the file that it is trying to open.

When this is done through Finder it works - double-clicking on an associated file would not launch a second instance but the file name can be gotten through PB_Gadget_SetOpenFinderFiles(Callback).

OTOH running "open -a myapp.app --args file2Open.ext" in Terminal when an instance of the app is already running would also not launch a second instance but there is no way of getting the passed parameter "file2Open.ext".

In Windows I use PB's parameter functions then SendMessageTimeout to the running instance with a custom message and #WM_COPYDATA then send/receive the parameters through COPYDATASTRUCT.
Post Reply