Hi guys,
I stumbled over a strange error in one of my scripts. Here is a simple script as an example:
tell application "Finder"
try
do shell script "afplay '/Applications/Sound Utils/Sound Done!.aiff'"
on error
do shell script "afplay '/System/Library/Sounds/Purr.aiff'"
end try
end tell
The script works without any obvious error but, here are the script replies in AS Editor:
tell application "Finder"
do shell script "afplay '/Applications/Sound Utils/Sound Done!.aiff'"
--> error number -10004 -- A privilege violation occurred.
end tell
tell current application
do shell script "afplay '/Applications/Sound Utils/Sound Done!.aiff'"
--> ""
end tell
Result:
""
I checked many scripts with various ‘do shell script’ commands placed in a try block nested within a tell block. All scripts work without problems but, all show that error in the replies. Questions:
What is the meaning of the error “-10004 A privilege violation occurred”? For the purpose of this test, I gave the folder and sound file full privileges to everyone.
Why doesn’t it have any effect on the actual working of the scripts?
If it is an error, why doesn’t “on error” take over?
If the try block is taken out of the tell block, then the error disappears. Is there a rule that try blocks shouldn’t be nested within tell blocks? Here it is by itself:
try
do shell script "afplay '/Applications/Sound Utils/Sound Done!.aiff'"
on error
do shell script "afplay '/System/Library/Sounds/Purr.aiff'"
end try
and the replies:
tell current application
do shell script "afplay '/Applications/Sound Utils/Sound Done!.aiff'"
--> ""
end tell
Result:
""
I think mouramartins found the correct snippet, which I find quite worrysome for my own purposes.
Why the error isn’t trapped in the on error clause. It is however considered bad practice to do stuff in a tell block, that isn’t absolutely necessary to do there. In your case, just move the block outside the tell block of finder. I think mouramartins nailed it!
Which is unfortunate for me as I really want to leverage on scripting additons for speed gains, above applications tell blocks! I’m quite anxious now.
I can try to explain. When a do shell script is executed by the Finder nothing really can go wrong because the Finder has the same (console) user as the script itself. But what happens if I use an application that runs as root? For instance application “Bit Slicer” (which I use for memory lookup) runs always as root and when I do:
tell application "Bit Slicer"
do shell script "whoami"
end tell
The result will be ‘root’. That means that my script can bypass Mac OS X/Unix’s security and I’m able to do everything I want. So what my script needed to do was looking for an process that runs as root and tell it what to do. One of the things to solve these leaks is just not allowing to do a shell script by another process than itself.
So what you should do is just:
--when you're already in current application you don't need a tell block
do shell script "whoami"
--or when you're inside another application tell block
tell application "Finder"
tell current application to do shell script "whoami"
end tell
mouramartins, Bastiaan,
Thanks, that is quite clear now.
I agree generally with “not doing stuff” there. In my initial example, I actually “did stuff” but just for the purpose of showing that “on error” doesn’t trap that particular error. I still don’t know why.
However, most of the times, I like/need to put there more than just a short message for the user. Usually, I insert a “display dialog” with a more detailed message/explanation and, depending on the context, options to cancel, or do this or that.
Guys,
Regarding a “display dialog” inserted in a try block outside the Finder, do I have to tell the current app to tell the Finder to display the dialog, or put the dialog in a nested tell the Finder block?
Display dialog is an ‘odd’ command. For normal commands in a tell application block an event is send to the current target application. When the application can’t/doesn’t want to handle the event it is send to the parent (following the parenting chain). For a display dialog the command is send immediately to the system and a dialog is displayed in the target application context. Similar to commands like activate.
I think the display dialog is to be handled by SystemUIServer so I use a construct like this, I think it also speed up things a little!
tell application "SystemUIServer"
activate
display dialog "Testing"
end tell
I use to have try error block in there, but then I set a failed variable to true, and deals with the error outside the context of SystemUIServer, if the script is to quit, etc.
I think such an approach is wise, also for other tell blocks, as to not have events “pending” inside running applications.
I’ll use this construct in my current attempt to optimise a longer script for speed.
Regarding speed, could you point me to options to actually time the execution of a script between dialogs precisely. I haven’t done actual measurements yet, other than rough manual timing.
I don’t think that displaying dialogs that way will speed up your script much, but you will direct the events directly to where they’ll end up anyway. And you can be pretty sure that the dialog will turn up, whatever space or screen you are in, it will be visible, and rendered fast, since it is SystemUIServer that takes care of such things, and no pending events on the way, in for instance a busy finder, or busy SystemEvents, or whatever app you are using will slow it down.
Edit I see below that there are diverging opinons about this matter, but I’ll stick to my way, as I am happy with it. I think I have experienced that the display dialogs can be slowed down, at least when addressed through System Events, or Finder.
Like i said in my previous post, display dialog doesn’t follow the parenting chain like normal events do, so there are no ‘events pending’. The event is sent immediately to the window server, not to systemUIServer, and display dialog for current application, finder or any other application shouldn’t have any measurable time differences.
One thought has struck me: what if SystemUIServer is just another synonym for Window Server?
And I’d really love to see a log of the aetes travelling to the windowserver in both cases, to see if there are any difference!
I’ll come back to this subject, as I want to perform some other kind of tests, regarding localization, to see what kind of information is displayed, when calling display dialog through different applications.
When I tell Finder, SystemUiServer, or System Events to display a dialog, I get the buttons localized in my lingo. When I tell BBEdit to display dialog, then I get it in english. I can hardly interpret that in any other way, than that something more happens, than merely passing it over to the window server.
Window Server = WindowServer process including Quartz Compositor in it
SystemUIServer = the server for the menu at the top right corner of your screen.
I see! Well, I actually read in the book Applescript the missing manual that routing it through “SystemUIServer” was the fastest way. I have gotten complaints here, about routing the calls to display dialog through System Events.
And as I pointed out, there is a difference in the way the display dialog is localized, when calling it from BBEdit, than in the other cases.
I don’t know what to believe really, until someone drags up a reference to some documentation, or shows me a dump of the aete traffic.
There is no magic whatsoever: Show a dialog (with another process than SystemUIServer) and kill SystemUIServer and see what happens; the dialog remains and top menu will dissappear. Not recommended but look what happens if you kill WindowServer… aqua will die
I figured it all out! Before Coffee! Maybe SystemUIServer, is the app with the smallest dictionary for one thing, so the least overhead in resolving a tell block for a target application for AS is to call SystemUIServer.
That display dialog is implemented in Standard Additons.osax is a fact! But there are data passed along as well, from the current application, as my test with BBEdit showed.
I don’t want to kill my window server right now. I take your word for it! But the dialog, is killed when I kill SystemUIServer!
The one thing I seem to disagree with you about at this moment, is that data is passed a long, before calling Standard Additions.Osax directly, avoiding the parent chain. But that was never mentioned really.
( Unless you are using terms from. But that isn’t the question here. )
How sloppy of me! Well Stefan is there any rational reason for having the display dialog in a tell “SystemUIServer” block to invoke the display dialog as fast as possible?
I 'm thinking that maybe the aetes sent to SystemUIServer, either has higher priority, or that SystemUIServer, is running all the time, so it is latent in memory, and faster to call, and even given priority when it comes to memory as it deals with pages of it, in the user interface. That such factors may make it a faster renderer of display dialogs, as the over all process goes quicker with it run time.
I see, At least I believe, that the process being adressed in a tell block, is addressed in some way; that even if no resources of the targeted app is used, ( I am talking about applications targeted by tell blocks only), a process of sending applevents are started. And the time for this communication channel to be established, would be dependent of the process status in real memory (by real memory, I mean active physical memory). I believe SystemUIServer to always be in physical memory, since it is about updating the UI. Therefore I believe SystemUIServer to be the fastest. Being the process that it is fastest to establish contact with, and therefore the fastest to delegate the display dialog request away to Standard Addtions.Osax. Even faster than the current application, as the current application may (theoretically) need to load some pages into real memory first.
Having pondered this, I think this hack, was established some years ago, when having less than a gig of memory was the norm!
But, say if the system is bogged down with some serious downloading, and updating spotlight meta data, while the macports ports tree is updated, (rebuilt), under such conditions, I think it to be noticable.