I promised it wouldn’t be too long before I returned to provide the results from my experiments into running EA scripts from an external application (or if you wish from an EA Add-In). If you missed the previous post on scripting may be worth reading first so that the current post is read in context.
Moving forward within exploring scripting capabilities let me start by providing some background information I discovered that will be relevant to the task in hand with the focus on user scripts. You will see below I have skipped stuff that I didn’t see necessary for the current experiments.
1. EA stores its scripts in t_script
When we want to run an EA script we need to know where they can be found. If you look into the EA database, and my suggestion would be to open a local EAP file using Access, you can find a table called t_script as illustrated below.
t_script – contains a range of scripts including user scripts
If you look through that table you see the following columns which as I interpret have the following meanings:
- ScriptID – a unique integer
- ScriptCategory – there are several categories with normal human readable names and some GUID looking numbers (!) which including user scripts(indicated by the category with the value 605A62F7-BCD0-4845-A8D0-7DC45B4D2E3F). You can also see other scripts such as those used when building code
- ScriptName – once again either a human string or a GUID looking number
- ScriptAuthor – another GUID looking number – not sure where this points to yet. I’ll have to add this in when I find it but didn’t seem important at the time.
- Notes – specifies the script name, type and language e.g.”<Script Name=”myScript” Type=”Internal” Language=”VBScript”/>”
- Script – contains the script code in plain text form for user scripts. When necessary I’ll have to check out the use of this for other types of scripts.
2. Extracting the script
If we want to run any of the user scripts we need to read the t_scripts table and extract the required script. The method I have used was to:
- Read the rows from the table, filtering on script category
- Get the script name
- For the selected script, extract the text from the Script column
3. Checks before running scripts
INCLUDES – If you look at scripts in EA you will see that some will include other scripts (e.g. INC). If we are running scripts within EA this is not a problem provided they exist within the EA context, however as we will see below, if we are running them elsewhere we need to ensure that we include ALL the relevant code.
RUN TIME OBJECTS – when running scripts within EA use is often made of the following run time objects:
- Repository – current EA repository
- Maths – the Cephes maths library
- Session – which provides functions to interact with the user through the EA UI
If you are executing your scripts in another environment then you will need to supply the relevant references if required; note that the session object is purely for use within the EA script running environment.
Running scripts from the outside
With that bit of background we are now ready to look at running an EA script under the control of our “external” application. Why is this an issue? Can we not just ask EA to run the script for us? Well so far I cannot see a way to interact with the EA script engine via the automation interface. Hence, the solution I have used (and I believe used by many others) is to provide my own instance of the script engine, extract the relevant script code and execute.
This isn’t as difficult as it sounds, although my voyage of discovery was interesting – and as seen from various posts on the Sparx Forum and Stack Overflow shared!
As far as I can determine EA uses the Microsoft windows scripting engine. Which I believe is MSScriptControl – which means that VB Script and JScript scripts written for EA can be run by using this control.
To run a script, we can use an instance of this class, set the relevant attributes and call the run or execute function. So within our application we can:
- Create an instance of MSScriptControl e.g. myScriptControl
- Specify the script language e.g. myScriptControl.Language = “VBScript”
- Set the script code using the relevant text (note: this will need to be complete with any includes expanded. e.g. myScriptControl.AddCode(ScriptCodeText)
- If required pass objects that will be available to the script using the AddObject method e.g. myScriptControl.AddObject(“myObjectName”, myObjectValue, True) adds a name/value pair and sets this as a global value
- If required pass parameters to the script. This is done by setting up an object array containing the relevant arguments e.g. ArgumentObjects. Remember that the scripting languages are loosely typed so they have no explicit knowledge of typing
- We can then run the script and for functions capture the result e.g. myResult = myScriptControl.run(“myScriptName”, ArgumentObjects)
Pulling it all together
So with that background I put together a simple program to run a script. The application provided a means to enter a script and run it. This allowed me to verify that the mechanism worked fine without any interactions with EA. However, I need to remember to do things link reset the scriptcontrol if I reuse it (myScriptControl.reset)!
It is also worth noting that I recently saw that there are some observed issues, for example – adding code will automatically execute code – I have only seen this issue when executing the script control within an EA Addin, it seemed to work fine when operating in a standalone program but that doesn’t mean there aren’t instances where this is not the case (the joys of software), hence I need to explore further!
But in the meantime, onto testing with EA – which involves the following steps:
- Open an EA Repository
- Get a list of user scripts
- Select and run a script
- View the result report
As it turned out I skipped writing a simple windows application as I was confident that would work, so went straight to writing a small Add-In that would perform these tasks. So no need to open the repository just the steps that followed.
My simple Add-In basically lists the available user scripts and provides a means to inspect and run the script.
Script Tester Menu
The form that presents me with a list of scripts (as well as providing a option to refresh the list) is illustrated below.
Script tester addin displays a list of scripts that can be selected
The user can select a script from the list, and inspect the details:
Details of selected script – script can be run by pressing run script button
And if they wish run the script, for example as below.
Results from running the simple script
I am pleased to say that it presented the same result as when running the script natively within EA.
So using this approach there is a a means to run EA scripts under our control, demonstrated with this EA Add-In, and I’m confident it will work from the outside with a windows application, albeit with care regarding the objects that are being expected.
Points to note
Just to recap on the some points for running scripts using the script control. You need to:
- Ensure that the code provided is complete
- Reset the script control before use
- Pass any required object to the script – note that session is not available and if libraries are required you are responsible for ensuring that they are accessible
- Provide any required arguments as objects – NOT typed
- Capture the results
Nearly there or not!
If I refer back to my diagram in the last post (repeated here for reference), that illustrated all the tests I wanted to explore.
Overview of scripting scenarios to explore
We have covered all cases 1 to 6 – albeit that there is ongoing work in checking some potential issues with case 6.
Case 7 – calling our Add-In from a script when working within EA
So what about the EA script control (not our own script control) calling an EA Add In. Just to be clear this is a normal EA script running within EA. Is there a way? Well I’m still working on this. I’ve posted and had some interesting observations which I have posted on the Sparx Forum.
This case has presented some interesting windows programming issue which has forced me to spend more time that planned looking into windows processes, but then that is the fun of exploring.
Overall for the most likely use cases all works as one would hope. It is the edge cases that I thought I needed to explore that have raised some issues and I’ll be looking into:
- Feedback I’ve received on how to resolve case 5
- Unwanted code execution issues in case 6
- Finding the correct reference for case 7
I hope to report back soon with my findings for these cases.
In the meantime, if you have some answers do join the dialogue here or on the forums. For those happy with other scenarios I hope you have found this useful.