AppleScript handler not working when called from within tell Finder block - error-handling

Learning to work with handlers in AppleScript I've run into an issue. Currently I have trimmed my application to call a handler when ran but currently I get an error:
error "Script Editor returned error -1708" number -1708
When I compile I have no issues. When I try to research for a solution I'm unable to find a reason why this doesn't work under the application Finder. To memory, I recall the on run must be declared last in the application.
the code:
on checkForRebels(tieFighter, starDestroyer)
display dialog "dark enough" as text
end checkForRebels
on run
tell application "Finder"
set the starDestroyer to (choose folder with prompt "Please select the Destroyer")
set tieFighter to items of starDestroyer
checkForRebels(tieFighter, starDestroyer)
end tell
end run
I tried searching for
applescript items throw error when passing to handler
but I returned Apple's Working with Errors which doesn't answer my question. When I review Apple's documentation About Handlers I don't see anything disclosing what the issue should be.
When I modify my script to:
on checkForRebels(tieFighter, starDestroyer)
display dialog "dark enough" as text
end checkForRebels
on run
tell application "Finder"
set the starDestroyer to (choose folder with prompt "Please select the Destroyer")
set tieFighter to items of starDestroyer
end tell
checkForRebels(tieFighter, starDestroyer)
end run
it works without any issue but why does the handler checkForRebels() not work in application Finder's tell block? When I call a handler do I have to always do it outside of an application for it to work?

When you are calling a handler from within a tell block or other handler, you need to specify "my", otherwise it is looking for that command in the Finder dicitonary.
my checkForRebels(tieFighter, starDestroyer)
From the Applescript Language Guide Calling Handlers in a tell Statement:
To call a handler from within a tell statement, you must use the
reserved words of me or my to indicate that the handler is part of the
script and not a command that should be sent to the target of the tell
statement.

Related

Applescript to open Safari

(newbie here) I'd to be able to save an applescript file as an app to use to open Safari, I cobbled together this from some old posts I found, it's not exactly what I want but it worked ok, however today it stopped working giving an error "The variable theURL is not defined."
If anyone could help me out with a better script that would work on Monterey I would be really grateful. Also, when I save as an app - should I select 'Stay open after run handler' or 'Run-only'? It just needs to open Safari when it's clicked, I don't need it to really open any particular page. Thanks in advance!
tell application "Safari"
activate
try
tell window 1 to set current tab to make new tab with properties {URL:"https://google.com.au"}
on error
open location theURL
end try
end tell
I cobbled together this from some old posts I found:
tell application "Safari"
activate
try
tell window 1 to set current tab to make new tab with properties {URL:"https://google.com.au"}
on error
open location theURL
end try
end tell
A lot (virtually all) applescripts you see online make overuse of try blocks, which, apart from being completely unnecessary, are problematic in a number of ways, including making debugging more difficult. I'd advise taking out the line try, and everything including and between the lines on error, and end try.
Without those lines, you'll probably get a different error message, which was being masked by the try block. It most likely that window 1 didn't exist, which would be the case if Safari had already been running and didn't have any windows open. It would have then thrown an error, forwarded the script on to the on error block, where open location theURL then, itself, threw an error because theURL hasn't been defined.
I don't need it to really open any particular page
Then all you need is this:
tell application "Safari" to activate
If Safari is already running without any open windows, all this does is bring Safari to the front; it doesn't open a new window for you. If you need to create a new window you can usually do this:
tell application "Safari"
make new document
activate
end tell
However, this will create a new window even if there's already a window open, which might not be what you want. To create a window but only if a window doesn't already exists, you can do this:
tell application "Safari"
if documents = {} then make new document
activate
end tell
I suspect this is the script you will want to use.
Should I select 'Stay open after run handler' or 'Run-only'?
No and no. The first option prevents your app from quitting without explicit instruction to do so, which isn't needed in this case: you simply need your app to open, start Safari, then quit. The last option prevents you from making any edits to the script in the future, which, again, probably isn't what you want.

Create a new PSD file and copy/paste new layer with AppleScript

I try to make a code assembly to create my own applescript to create an image in Photoshop but unfortunately I have an error and I can't find where it comes from.
The first part of the script works, the random image is well copied to the clipboard but the rest is problematic.
-- Select random image
tell application "Finder"
set bg_img to file (random number from 1 to (count files of folder "HD:Works:Club:LAYERS:0-BG")) of folder "HD:Works:Club:LAYERS:0-BG"
end tell
tell application "Preview"
activate
open bg_img
end tell
-- Select and copy image to clipboard
tell application "System Events"
tell process "Preview"
keystroke "a" using command down
keystroke "c" using command down
end tell
end tell
-- Quit Preview Application
tell application "Preview" to quit
tell application "Adobe Photoshop 2022"
-- Create a new document
set docRef to make new document with properties {width:1200, height:1200, resolution:72}
tell docRef
-- Unlock the background layer and fill it with gray color
set background layer of layer 1 of docRef to false
fill selection with contents {class:RGB color, red:200, green:200, blue:200}
end tell
end tell
-- Paste image to new layer
tell application "System Events"
tell process "Adobe Photoshop 2022"
set newLayer to make art layer with properties {name:"LayerA"}
keystroke "v" using command down
end tell
end tell
Ok, a compilation error; I got it now. Try this:
-- Paste image to new layer
tell application "Adobe Photoshop 2022"
activate
set newLayer to make art layer with properties {name:"LayerA"}
end tell
tell application "System Events"
tell process "Adobe Photoshop 2022"
keystroke "v" using command down
end tell
end tell
Remember, you use a tell application "NAME" … end tell block to 1. tell AppleScript which app to send commands to, and 2. the app from which to get the custom terminology (keywords) for commands and objects.
Thus your tell application "System Events"…end tell block uses SE terminology and commands. The tell process "Photoshop"…end tell block inside it is still addressed to System Events. process is an SE-defined keyword for an SE-specific object. Likewise keystroke is an SE-specific command.
To make a new art layer in Photoshop, you have to put that command inside its own tell application block which is targeted at PS.
Yeah, AppleScript is often confusing. And System Events is 10× more confusing than that, thanks to it being not-obvious what is GUI Scripting and what isn’t. Good luck.
--
p.s. I’ve a feeling the tell process block is totally redundant, and is only necessary when using GUI Scripting to manipulate an app’s windows. IIRC the keystroke command doesn’t know or care what app receives those keys, in which case what’s important is that you activate Photoshop before you start “pressing” keys. I’ll leave it to you to determine if you can discard the tell process.
p.p.s. AppleScriptable apps usually don’t include cut and paste commands, usually ’cos they already provide far better ways of getting and setting content. Photoshop, however, does. So if you’ve not already tried it, try inserting a paste command at the end of your “tell Photoshop” block, then comment out the “tell System Events” block, and see if that works for you. If so, you can get rid of that System Events block entirely!
p.p.p.s. It’s also worth investigating PS’s dictionary further, to see if it can open and place your “bg_file” directly. If so, you can eliminate the “tell Preview” and the rest of that System Events horridness too!!

Why does my VBA procedure sometimes stop in debug mode?

I have a button click event in an Access form that sometimes opens the VBA editor with the 'On Error...' line highlighted as if it is in debug mode. I can F5 to continue the rest of the procedure and it works fine.
It doesn't happen everytime. It seems random except there seems to be a pattern that it happens on the first click of this button right after the file is opened. Not everytime though.
Any thoughts on this or previous experience with the same thing happening and subsequent solution? What might be causing this? It's a terrible user experience.
Well, before running any code (hold down shift key during startup to prevent any code from running).
Now, ctrl-g (jump to VBA IDE). Now from tools. Choose
debug->Clear all Breakpoints
Like this:
Now, open up any code module - hit enter key to "dirty" the code. Now choose debug->Compile (first menu option). It will say Compile "my app name".
Make sure the code compiles. If it does not, then stray break points can still exist.
Next up, you need to check/change the default behavior for a error.
While STILL in VBA editor/IDE
From menu bar choose tools->options. The default is "Break on Unhandled errors"
If you have break on ALL Errors? Well then code that even assumed to trap or even on-error resume next code it BLOW UP and stop. Often developers will say try for existence in a collection, and we error tap to "mean" the element is not in that list. However, the THIS assumes that the default Error trapping setting was not change.
So, double, and then triple check this setting. You can develop for years, and even have some code ASSUME to error out. But that years of development code assumed the default (break on unhandled Errors. If you have break on all errors, then your are toast, and you find all kinds of breaking of code. (the idea of that option is to LET you debug code with error handling without having to disable errors. And with say on-error resume next, you in effect can't debug parts of code anymore.
Now, if above steps don't fix your issues?
Then the next step is to de-compile your application. This will remove the compiled (binary) part of the application. Once you do this, then you do a full re-compile.
To de-compile, you can't do this from the IDE, and you have to use a FULL qualified path to your existing version of access. Say like this:
"C:\Program Files (x86)\Microsoft Office\Office14\MSACCESS.EXE"
"c:\MyCoolApp\Invoice.accDB" /decompile
Now, when you run above, you REALLY must not let any startup forms or code run. (hold down shift key. Now exit access/application. Now re-launch (and again no code to run on startup).
Now, at this point I high recommend a Compact+ Repair (and AGAIN no startup or code to run). So even on the C+R, you have to hold down shift key.
If you during the decomp, start application, then C+R allow ANY code to run, then you have to start over again at the first decompile step.
Ok, now you done the C+R. Now ctrl-g, and now debug-compile.

VB.NET: Stop smoothly in debug.assert (false) line

I always write code like this:
If SomethingIsTrue Then
'DoThis
ElseIf SomeOtherThingIsTrue Then
'DoThat
Else
Debug.Assert (False)'Doh!! I forgot to handle a certain condition
End If
In VB6 this worked great. During testing my app in the IDE, it just stopped in the Debug.Assert(False) line, and I saw where I missed something.
But VB.NET does not stop there but instead gives me a huge messagebox. This seems to be standard behaviour for Debug.Assert.
I have 2 questions, please:
1) How can I make it stop smoothly in that line instead of showing the messagebox?
2) How can I make it so that at runtime (!) no messagebox is shown but instead my application just keeps running without stopping or showing a messagebox?
Thank you!
I would write something along this line:
if debugger.isattached=True then
debugger.break
end if
Just wrap it in a shared sub, and you can simply call it in the else statement.
The code is typed without visual studio at hand, so I hope it will work.
How can I make it stop smoothly in that line instead of showing the messagebox?
Just click Retry on the message box that pops up. From MSDN:
Clicking Retry sends you to the code in the debugger if your application is running in a debugger, or offers to open a debugger if it is not.
Clicking Ignore will, well, ignore the message.
How can I make it so that at runtime (!) no messagebox is shown but instead my application just keeps running without stopping or showing a messagebox?
I don't mean what you mean with at runtime, since all asserts happen while your code is running, hence at runtime.
If you mean that asserts should be ignored while running your application without a debugger, just make a release build instead of a debug build. The Debug.Assert method works only in debug builds, and the point of debug builds is that they are easy to debug.
If you want nonetheless suppress the message box, see Customizing Assert behavior:
For example, you could override the TraceListener.Fail method to write to an event log instead of displaying the Assertion Failed dialog box.
To customize the output in this way, your program must contain a listener, and you must inherit from TraceListener and override its TraceListener.Fail method.

Showing DialogBox and MessageBox from DLL

I'm buisy on a DirectX10 game engine and i'm having a problem which has nothing to do with DirectX :P The problem is that in the DLL which contains the engine sometimes a DialogBox is called, just like you would do in normal win32. With the only difference that instead of the HINSTANCE i use the HMODULE which i get when loading the DLL.
Everything seems to be working fine, if i step through my code with F10 (Visual C++ 2008) i can even see it going through my DlgMessageProc function and do everything it should do. The only weird thing is that no dialog is shown and that all of a sudden it jumps out of the message loop and just continues with the rest of the code???
Weirly engough I have the same problem when calling MessageBox from inside my DLL, I get no errors, everything seems to be working fine but no window is shown, nor is the code halted (as normal with messageboxes)
The funny thing is that I have some code from a book which uses the same basic architecture as me and if i compile that everything shows just fine??
So my question, is there any hidden option, pragama comment or other thing i should look at if i want to be able to show MessageBoxes and Dialogs from my Dll?
No as i thought, chaning the manifest doesn't help at all. I also created a separate project where i just test the dialog and its proc function and there everything works perfect (links to a .exe instead of dll)
In the visual studio resource editor's property page for the dialog resource there should be an option in which you can specify - "No Fail Create: True".
Usually dialogs fail to create because a common control cannot be created - usually because InitCommonControlsEx has not been called. Setting the No Fail Create flag lets you see dialog and determine which controls are missing.
Other things to check:
Is there a message in the debug window about a first chance exception? Perhaps its 'jumping out' because of an exception that is being caught and silently handled by Win32. Turn on debugging of first chance win32 exceptions in the Dev Studio exceptions dialog to track that down.
Even this wouldn't explain how a MessageBox call would fail to create a message box.
The only times Ive seen MessageBox fail to work were when:
Resource leaks had made the process run out of available user32 handles - have you checked your apps handle counts using task manager?
the system was in the process of being shut down. Have you called PostQuitMessage and then tried to create a dialog/MessageBox?