ESAPI Guide: 5 steps to start scripting, including Citrix users

João Castelo
14 min readJul 9, 2020

Hey guys!

In this article, I’ll show what in my experience are the basics to start writing and running your scripts with ESAPI (Eclipse Scripting API). The following lines are coded for Eclipse v15.6 libraries, but they should be reusable in most versions above 11.0
All items are based on simple read only projects covering how to write and run:

  1. Hello World in Visual Studio.
  2. A Single file script in Eclipse for single patient running in Eclipse user interface;
  3. A Compiled script as library (a.k.a Binary Plugin) for single patient in Eclipse UI;
  4. An Executable that iterate in multiple patients from the planning database (using citrix);
  5. The Usage of Visual Studio Git to manage two versions of the previous executable.
Photo by Max Duzij on Unsplash

You don’t have be a code master to script in Eclipse. Simply google it, try it, make mistakes, try again until you write one that works. Definitely you’ll need to learn C #. And there are cheap courses on Udemy that are more than enough.

First of all let’s download the visual studio IDE which is basically mandatory. You can download it on your personal computer or on your work computer if IT allows.

Install it along with the following workloads:

The C# very basics:

Printing hello world in Visual Studio and C #:

Open visual studio and create a new project:

Check that is a Console (.NET Framework) solution.

We’ll choose .NET Framework version 4.5.

Check the Program.cs file:

Declaring a variable:

Inside the brackets, insert the following line:

string message = "Hello World";

In this statement you’re telling the system to store in the memory a string that has message as it’s name.
Every time you want to reuse the message “Hello World” you can refer to the message variable.
First we will print the message on the console (cmd).

Console.WriteLine(message);

Press Ctrl + F5 :

It’s done, your first program is running!

MessageBox

Until our first executable program with ESAPI, we are not using the command line to print our results. Instead the windows MessageBox will help us with this task.

Append the following line:

MessageBox.Show(message);

Right click the error in red:

Left click Quick Actions and Refactorings or Ctrl+. (This is an useful shortcut);

Add the reference to the Presentation Framework:

Check the start of the file Program.cs

Now it contains the reference to the Presentation Framework library.

And the error goes away! Press Ctrl + F5 once more.

You have just successfully used the MessageBox from the Windows Presentation Framework, and you no longer need the console to understand your code outputs for now.

Digging in ESAPI:

ESAPI libraries link the TPS to C# in the same way that the windows Presentation Framework library connects C # to OS’s presentation features. The libraries contain code that intermediate two or more systems so we don’t have to worry about it. In ESAPI there are classes that connect the Eclipse objects to the code presented to the user. So if we want to get information about the patient’s name with ESAPI, we have to access a C# Patient object.

What is an Object:

In short, it is the instance of a more complex data structure than the basic types. It comes from a class. Every class is traced to basic types like numbers, strings, booleans. The cool thing about visual studio is that when you have an object, you can access its properties names before compiling the code.

Here is an example, I`ll create a class

and it will have an ID, age and priority.

Now we are going to create an instance of the patient, referenced by the variable jack.

Patient jack = new Patient("123",56,1);

Hence, jack has id 123, 56 years old and priority 1.

This was assigned to jack via the class constructor, by the 3 arguments inside the parentheses:

We can access the properties and functions using a dot after the object, the intellisense helps a lot.

If you’re a bit lost, this is the code you want to run.

In visual studio press Ctrl + F5 :

Result of the last MessageBox, this is jack info.

ESAPI in practice:

This is a table that summarizes what I think are the most important features of each type of ESAPI scripts.

Plugins:

Every script relies on the Eclipse installed in a workstation. If you run a script from within the eclipse, it only accesses the information from the patient whom UI window is open. There is an object called ScriptContext that links the patient elements to C #.
When using plugins, Eclipse itself compiles the code, hence we are not going to use the Main () function as entry to the code, rather it is going to be the Execute function, in the Script class nested in the namespace VMS.TPS.

ESAPI Visual Studio Project from Scratch:

To explore our first plugin, create a new project in the same way as hello world. However it will now be a Class Library (.NET Framework) named HelloWorldPlugin.

Being the project created, right click in references:

Now you have to find the libraries that connect Eclipse to C#.

In general, the VMS.TPS library is located on the computer that Eclipse is installed. In the following folder:
C: / Program Files (x86) / Varian / RTM / version / esapi / API

If you are a CITRIX user this can help you find the files:

Access the CITRIX computer (Useful Trick)

In the eclipse UI, open External Beam Planning / Tools / Scripts

Left click on Open Folder:

Copy the files to your local disk where your visual studio is installed. They should be at the same path we described before:

Now we are ready to write the first lines of the script:

It is mandatory for ESAPI plugins to have this template, so feel free to reuse this:

Replace the original code in Class1.cs with:

The same thing that happened to the MessageBox is happening to ScriptContext! Visual studio will complain that it does not exist. Then click Ctrl +. and solve the problem.

Now you have the reference to the library that connects Eclipse to C#.

You can also add the following line before the VMS.TPS namespace:

using VMS.TPS.Common.Model.Types;

The VMS.TPS.Common.Model.Types library has classes related to VMS.TPS special data structures, like VVectors, DoseValuePresentation and others.

Explaining the Script:

Let’s write the first lines in the single file plugin. And then run it on Eclipse (Tools/Scripts).

The code will do the following: The context, which is the open window, has an External Radiotherapy plan that is currently open. We will access this plan through the script and we will create a message variable with the name of the plan. Then use a MessageBox to print that plan name.
This is the final code:

Use the windows forms from the Presentation Framework, not from Windows Forms, it won’t work because this library is not loaded in Eclipse Assembly.

Open a patient through External Beam Planning. Anyone who has a calculated dose plan:
In my case a Radiosurgery with multiple targets:

First Test:

Locate where the Class1.cs file you’ve just edited is. If you’re a citrix user, you must transfer the file to the client or the virtual computer that citrix is connected.

Run the Class1.cs file, double clicking the file or pressing run:

We successfully ran our first single file script.
Now try changing the string that contains only the Id of the plan to the last name of the patient and the plan.
Replace the line that declares message with this line:

string message  = context.Patient.LastName + " " + plan.Id;

Save and run it again:

This template can be as complex as you can get in one file!

Single File Plugin Limitations:

You cannot reference libraries that are not pre-installed in Eclipse. This means that if you want to make a plot directly in C# you won’t be able to, since it needs an external library. (In other article I show how you could do indirectly).
Limit yourself to a single file. Code separation is very important in C # and this is completely blocked by the structure of the single file plugin. There are files that should be separated that are together, generating 10,000 line scripts.

We will often need to make graphical interfaces for our applications. WPF is a good solution, however it does needs two or more files, then single file scripts are not suited to this task.
To solve this problem, Varian allows you to create compiled scripts, meaning you can transform your code into a fake library. Which has an entry point equal to the single file plugin and is called a binary plugin.

Script Wizard:

In this guide, I’m not using the ScriptWizard program from Varian, because I do not like the split of the project from plugin files it does. However, it is simple enough to create a project with it.

You can find it in the computer that Eclipse is installed:

C: / Program Files (x86) / Varian / RTM / version / esapi /ScriptWizard

Warning: If you’re a Citrix user, remember to save the project in the Client disk, so you can open it with Visual Studio.

This two folders are created

Acess the Projects folder and open the .csproj file:

There it is!

You still have to reference the libraries by copying them to the computer Visual Studio is installed if your Eclipse is not local.

Creating our first Binary Plugin:

To enforce our rhetoric, we’ll use a external library called RandomNameGenerator to test this binary plugin.

Continue with the HelloWorldPlugin and the Patient you are testing:

Right click references again, but now click in Manage NuGet Packages:

Go to browse and search for RandomNameGeneratorLibrary.

Install it

Now change the code in Class1.cs to:

Footnote:

Notice that I accessed the patient’s name through the Plan / Course / Patient, no longer from the Context. Ideally, you should use as little context as possible to be able to reuse code in executables, where there is no context.

Testing what I’ve said:

After I saved the Class1.cs and then tried to run, it gave me an exception. And referencing to the lack of the RandomNameGenerator Library.

Building the code (very important):

Go to project properties or press Alt + Enter and Change the project assembly name to HelloWorldPlugin.esapi:

In the Build options tab, change the platform target to x64, also change the Output Path to blank:

Save it (Ctrl + S), press Build/Build Solution or Ctrl + Shift + B.

If you changed the path of output to blank, the projected was built in the same folder of Class1.cs. If not it should be in bin/x64/Debug

Run it via Eclipse UI.

Run it one more time:

Looks like the random function is really random (pseudo) hahaha!

The folder of the solution now has a lot of files:

KEEP THE FILES THAT THE SCRIPT REFERENCES IN THE SAME FOLDER.

Weird Bugs and Memory in Binary Plugins?

If any of these dlls is missing, the code would crash if you reboot Eclipse. If you keep it open, the script will keep working because the script is loaded in the assembly memory.

This also means that if you build one more time it is not going to change the script functionality. As much as you want and think this is weird, if visual studio is building into the folder you’re getting the file, it will not build, a message of block by ARIA RadOnc will pop while you build.

The solution is to reboot eclipse or change the project assembly name.

Take home message:

Binaries solve the problem of external libraries and code separation, they allow the creation of WPF applications, meaning that you can create your desired graphical interface.

The downside is the need to restart eclipse or change the assembly name for rebuilding after any change;

Executables:

If you’ve made this far, you are interested in exploring the database.
The executables work just like the first example of C # that you build and run directly from the computer. It opens the console or a window to log about the execution, so we finally will get rid of the MessageBox.

The VMS.TPS library connects C # to patients via the VMS.TPS.Common.Model.API.Application class object. This library finds the database inside the computer that has Eclipse installed, so for CITRIX users you will compile on your computer with visual studio installed, and copy all the files that come with the compilation to the CITRIX computer.

Coding:

Let’s create a new .NET Framework console application:

Reference once more the VMS.TPS libraries, just like in every example:

Write the code for the executable that search all patients in the database and prints the Id of the plans in which the calculated dose is valid on the console:

The [STAThread] flag is important, to secure we are only using a single trhead, mandatory in ESAPI.

Use the same build configurations from the binary project:

Save it and build with Ctrl + Shift + B.

If you have a local eclipse, you just check the executable in the folder and double click it:

However, if the eclipse is CITRIX you’ll have to copy the folder to the Citrix computer.
Use the same trick taught before to both copy and execute.

ExternalBeamPlanning /Tools /Scripts /SystemScripts/OpenFolder → Ensures access to the CITRIX file explorer that has Eclipse installed.

Double-click it. The script will print the name of the plans which have valid dose for each patient. For each enter that the user presses it iterates to the next patient.

Note #1: The executable needs to run in the local disk of the computer that has an Eclipse installed.

Note #2: Every patient needs to be closed after the iteration. That’s the reason of the line app.ClosePatient().

We are pretty advanced now with our executable, but imagine if you want to get those plans for a group of patients that you have already saved in a spreadsheet. These patients have a unique ID. And you’ve exported the IDs line by line to a text file, Ids.txt:

1235
225
12358
7777
8880
5555

This is where git management will become important!

Using git to save time:

We won’t need to create another project, we’ll just create another version of the MultiPatientExecutable solution.

This other version will be a branch of our original code.

To start branching our project, left click on the blue lower-right corner arrow in visual studio.

Click in Git:

The following screen will pop in the solution tab:

And this will show where the Add Source Control was:

Left click, on the upper arrow in the master side, and start a new branch:

The branch will be named ListOfPatients, and is going be branched from the recently created master. Go ahead and click Create Branch.

Now you are in the ListOfPatients branch, and all changes in the code will be affecting only this branch and not the master branch.

Now what you can do, and should, is that in each change in the project, you should not save with Ctrl+S anymore, but rather add the changes to the git version control, and if you are comfortable with them, they should be committed.

Let’s make a radical change:

Replace the Program.cs file content to the following:

Now add clicking on this pencil:

Write a message to be the commit’s description:

Check the changes, click in Program.cs:

Press commit all:

Now your branch is updated.

Build it again with Ctrl+Shift+B.

Run the program again:

Find the file containing the Ids:

And check the output:

It’s finally over !!

Photo by Xan Griffin on Unsplash

Thank you for your attention and hope you’ve learned something!

Check the other two articles I’ve written.

Don’t cry trying to learn WPF.

Executables are overpowered:

References:

--

--

João Castelo

Radiation Therapy Medical Physicist and Programmer