Is there a way that a Xojo app can detect that another application (Excel or Photoshop, for example) is currently open or not open on a Mac?
Public Function ListOfRunningApps(backgroundOnly as Boolean = true) as String()
'osascript -e 'tell application "System Events" to get name of (processes where background only is false)'
Dim res() As String
#If TargetMacOS
Dim s As New Shell
If s<>Nil Then
If backgroundOnly Then
s.Execute("osascript -e 'tell application ""System Events"" to get name of (processes where background only is true)'")
Else
s.Execute("osascript -e 'tell application ""System Events"" to get name of (processes where background only is false)'")
End If
If s.ErrorCode=0 Then
res = s.Result.ReplaceAll(" ","").ToListOfStrings
End If
End If
#EndIf
Return res
End Function
with
Public Function ToListOfStrings(extends aString as String, aSeparator as string=",") as string()
dim i,j as Integer
dim res() as string
j = CountFields(aString,aSeparator)
for i=1 to j
res.Append NthField(aString,aSeparator,i)
next
Return res
End Function
Thanks, Jean, for jumping in. I will give this a try; I hope today. If it works for me, I will label it as the Solution.
Another possibility using Declares:
Public Function ApplicationIsRunning(bundleID as string) As Boolean
Declare Function NSClassFromString Lib "Foundation" (name As cfstringref) As ptr
Declare Function getCount Lib "Foundation" Selector "count" (obj As ptr) As Integer
Declare Function runningApplicationsWithBundleIdentifier Lib "Foundation" Selector "runningApplicationsWithBundleIdentifier:" ( cls As ptr , bundleIdentifier As CFStringRef ) As Ptr
Dim NSRunningApplication As ptr = NSClassFromString("NSRunningApplication")
Dim runningApps As ptr = runningApplicationsWithBundleIdentifier(NSRunningApplication, bundleID)
Dim c As Integer = getCount(runningApps)
Return c > 0
End Function
Usage:
Dim isPhotoshopRunning As Boolean = ApplicationIsRunning("com.adobe.photoshop")
Dim isFinderRunning As Boolean = ApplicationIsRunning("com.apple.finder")
Dim isExcelRunning as Boolean = ApplicationIsRunning("com.microsoft.excel")
Jeanās code does what I need. If anyone is curious about slight modification, in my version below I replaced the ToListOfStrings code with the now available method in Xojo: String.Split which modernizes his code a bit. In this context, ToListOfStrings is no longer necessary.
Greg, I will try Declares in the future for my interest. I have not used Declares and am therefore not very familiar with them
Protected Function ListRunningApps(backgroundOnly as Boolean = True) As String()
Var res() As String
#If TargetMacOS
Var s As New Shell
If s <> Nil Then
If backgroundOnly Then
s.Execute("osascript -e 'tell application ""System Events"" to get name of (processes where background only is true)'")
Else
s.Execute("osascript -e 'tell application ""System Events"" to get name of (processes where background only is false)'")
End If
If s.ErrorCode = 0 Then
res = s.Result.ReplaceAll(" ", "").Split(",")
End If
End If
#EndIf
Return res
End Function
Is the function for private or public code? In case of public code then your users will see the following message:
Why do you do a nil check after newing the shell? Thatās superfluous.
would be nice if someone could provide the same for windows and/or linux ?
does the code from Greg with declares prevent from showing this warning dialog ?
paranoia ā¦
Gregs code doesnāt use AppleScript so it wonāt show the dialog.
Is it not true that that warning message will ONLY run the first time you use the app. After that, you are no longer bothered?
I am still living in the world of Mojave so I do not know the depths of security harassment the current OS imposes.
Yes, thatās true. But if your users donāt know what the message is about they will deny the permissions.
Well, I tried Gregās suggestion and āsurpriseā it works. It is very fast and directly answers my original question although Jeanās proposal provides a lot of additional information that I can find useful in other situation. It is nice that the Greg approach does not popup the warning.
The real point for me is that I donāt have to understand Declares to use Gregās code. I just copy the code.
It is a slight nuisance to actually find the bundleID of whatever application you are interested in, but you can use Terminal to find it and the required command can be googled.
Example: osascript -e āid of app āMicrosoft Wordāā
Will return: com.microsoft.Word
One little warning: the ācaseā of the bundleID is important. com.microsoft.Excel and com.microsoft.excel are not the same. The former is correct and you have to supply the correct bundleID to get the right answer. So Gregās example will not work properly as typed.
Sorry. Donāt have excel here to test with so I guessed. Every other bundle ID Iāve come across has been all lower case.
The docs is also case sensitive:
http://documentation.xojo.com/Desktopbutton
found nothing while
http://documentation.xojo.com/api/user_interface/desktop/desktopbutton.html
returns information about PushButton on Xojo 2021r3.1ā¦
One potential problem with the Greg O solution is that it is not always easy in my experience to find out the bundleID. For the regular frontmost applications, this seems to be relatively straightforward. But relevant for me, in my use case, is trying to determine if KeyboardMaestroEngline is running.
Using the Jean YP technique, when KeyboardMaestroEngline in fact is running, I can see it listed in the background application list. From this, I can ultimately write the code to determine whether this particular app is running. But I cannot figure out what the bundleID of KeyboardMaestroEngline is and therefore cannot apply the Greg O technique to answer the question.
I would be interested if there were a way to get a list of the ābundleIDsā of the applications running rather than simply their names so I could figure this out for KeyboardMaestroEngline and perhaps other background applications should the need arise. Some of the background applications listed look like they are, in fact, the bundleIDs (com.apple.Safari.SandboxBroker) but KeyboardMaestroEngline ā and I would assume others ā are not actual bundleIDs.
The bundle identifier for Keyboard Maestro Engine.app is com.stairways.keyboardmaestro.engine
I would really recommend researching how declares work or investing in MBS plugins. In this modern day, I would suggest an answer employing Apple Script is the wrong answer (because of the usability and macOS security issues).
Hopefully this bundle identifier helps, if thereās anything else I can do to get you to flag Gregās declares as the answer and not use Apple Script please let me know!
That is great and solves my immediate problem. But how did you figure this out?
I would suggest an answer employing Apple Script is the wrong answer (because of the usability and macOS security issues).
This must be a big topic. I hear whispers about the problems with AppleScript, and it is not pleasant to use but I find myself āhavingā to use it for this and that. And it does not seem to ever actually āgo away.ā If you know of some great resources to read about this whole topic and what it means and what is the future of AppleScript and why it is such a security problem and can that problem be solved etc. etc. I would read it. I sense that this all remains murky. Sadly in my current project, I do end up using AppleScript. Not a lot but at critical junctions.
Hopefully this bundle identifier helps, if thereās anything else I can do to get you to flag Gregās declares as the answer and not use Apple Script please let me know!
I am sometimes conflicted as what to flag as the solution when two people provide different solutions. I might like one over the other but I have felt that I should be crediting the first viable answer. Is it even possible to change which answer you credit as the solution after the fact?
āhow Declares workā seems almost to be like opening a Pandora box into another language altogether.
Thanks for your help (and concern )
So the MacOS SDK offers a single method for d finding out if an application is running if you know the bundle identifier which I used above.
If you need to find by name, It would be fairly simple to get an array of all running apps and then look for a particular name, but thereās nothing that prevents a user from renaming an app, which could result in a false positive or negative. Heck, AdobeĀ® itself could rename Photoshop to Photoshopper and your app would break, but the chance that theyād change the bundle ID is pretty slim.
You open the app bundle and check the plist.
As soon as you update your computer to at least Crapolina you can experience all the joys of the stupid security yourself. The security feels like we are all trained as Pavlovian dogs to click and click and click. The computer doesnāt trust itself anymore.
The declares are for persons who know Objective-C. I donāt have time for that. Buying and using the MBS plugin is much easier.