This blog post will require a rudimentary understanding of how Windows CMD works.
The first thing that we have to talk about is the command line API for GoFiler. You can open GoFiler the same as every other program:
c:\..\>GoFiler.exe
This will open GoFiler if your command window is currently in the directory where the exe is located (or in the PATH environment variable). However, if GoFiler is already open (later referred to as having an instance of GoFiler running) this command will bring GoFiler to the foreground. What is actually happening in the background is that a new instance of GoFiler is created, gets the command line parameters, checks to see if another instance is running, and then passes those commands to the currently open instance. This will become important later on.
There are a number of flags that we can add to the command:
newinstance - tells GoFiler to start itself as another instance.
nogui - tells GoFiler to not initialize the frame and to just run the passed command.
openfile - tells GoFiler to open a specified file
runscript - tells GoFiler to run a specified script
commandfile - tells GoFiler that there is a file full of commands. This increases the amount of space you have available in the command line.
result - specifies a location for GoFiler to put a result file for the command being executed.
There are more commands but these few are a good starting point. You can see a full list of parameters by referencing the Legato documentation. The ones that we will use in this post are newinstance and runscript.
Next let’s take a look at how Legato can interact with the command line. The command line is a one way the user interface in with Legato in GoFiler. We can’t pass or print anything back to the command line, but we can get the entirety of the last command passed to GoFiler. If we need to leave a log or response for the user we either have to be an active script and use message boxes or other UI elements, or else we can create a log file to be read later.
The two Legato functions that deal with command line parameters are GetCommandLine and GetCommandLineParameter. The first gets the entire command line, while the second checks if a specific parameter exists and, if it does, returns the value of the parameter.
Now let us take a look at these concepts in action. Because this topic is fairly high level I’ve actually prepared two short examples that show the power and flexibility that working with the command line gives us.
The first example makes use of a script that Steve wrote about in a series of blog posts in June of 2017 (the first of which is here). He wrote a script that adds a button to the XBRL view which performs a test filing of the open XFR file. While you do not need to read the entire post, you will need the script from the blog installed in order for this example to work fully. Let’s take a look at our interfacing script:
int main() {
string a, b;
int rc;
a = GetCommandLineParameter("XFR-Location");
b = GetCommandLineParameter("newinstance");
if (a == "") {
if (b == "newinstance") {
ExitApplication();
}
return ERROR_NONE;
}
RunMenuFunction("FILE_OPEN", "Filename:"+a);
rc = RunMenuFunction("XBRL_TEST_FILE");
RunMenuFunction("FILE_CLOSE");
if (b == "newinstance") {
ExitApplication();
}
return ERROR_NONE;
}
Wow, that’s pretty short and sweet, isn’t it? Yes, it is short because we’re now leveraging previous scripts in order to add a level of automation. But wait, we need something else, don’t we? Yes, we do. You also need the line that is fed to the CMD window that I have open.
C:\Program Files (x86)\GoFiler Complete>GoFiler.exe
/runscript:"C:\Users\joshua.kwiatkowski\Desktop\10-Q\readcommandline.ls"
/XFR-Location:"C:\Users\joshua.kwiatkowski\Desktop\10-Q\xbrl.xfr" /newinstance
Now let’s break down what happens when we run this. First thing is that the command line starts GoFiler. GoFiler reads that we’re asking it to start a new instance, and opens a new window even if there is already an instance of GoFiler running. Next we’re asking that new instance to run the script (the one we just created up above). Finally, I’m feeding it a parameter named “XFR-Location”. This parameter is not a standard command line parameter, but is one that I made specifically for this purpose.
The new GoFiler starts up, and after everything has finished initializing it runs the script. We enter our main routine and create a few variables that we’ll use in the function. We then get the “XFR-Location” parameter from the command line. If one is not provided, a blank string will be returned. We check for that condition, and return if that is the case. We also check to see if we are a new instance of GoFiler. The predefined API options that are boolean values, that is existing or not existing, (newinstance and nogui, for example) will return a string of the name of the parameter. So before we return, we check to see if we are a new instance, and if we are we run the ExitApplication function so new instance of GoFiler exits after the script finishes executing. We’ll do this same check before we return at the end of the script as well.
After we check to see that we have an XFR filename, we run the FILE_OPEN function on the XFR file, opening the file up. This is a requirement for the Test File as XFR script, so we jump through this extra hoop. After the file is open we run the XBRL_TEST_FILE menu function, which is the custom function that Steve’s script added to the ribbon. Finally we close the file that we just opened. We close the file before returning so that if we haven’t created a new instance of GoFiler we are cleaning up the mess we make from opening a new file.
This script can also be run without the “/newinstance” flag. This will cause the already open copy of GoFiler (if any) to open the file, test file it, and then close the file. This can be problematic if the other instance of GoFiler has any active dialogs open so use with caution on production scripts that may have user input.
The other example I’d like to show you is a script that shows how you can run scripts in the background of GoFiler without interrupting what a user is doing or, if you so choose, without a user even knowing. Scripts that are called via command line and are passed to an already running instance of GoFiler are run in the background. So I made a script that collects the names of all the open files in GoFiler and prints it out to the Information View. However, this script could easily be modified to format the data and put it into a file instead.
Here is the script:
int main() {
string a[];
int count, num;
handle log;
num = GetEditWindowCount();
if (num > 0) {
a = EnumerateEditFiles(false);
log = LogCreate("Open Files");
count = 0;
while (count < num) {
AddMessage(log, "Open Edit Window %d: %s", count, a[count]);
count++;
}
LogDisplay(log);
}
}
And here is the command to run it:
C:\Program Files (x86)\GoFiler Complete>GoFiler.exe
/runscript:"C:\Users\joshua.kwiatkowski\Desktop\10-Q\backgroundtask.ls"
First thing we do is we get how many open windows there currently are in the instance that this command gets passed to. If there are any windows open, we get all of the names of the open files, create a log, and then put all of the names into the log. In this example we then display the log in the Information View, but you could easily change this to place the log into a file.
Automation seems to be a holy grail of progress. It seems like no matter how much we can make a process simpler or more automated, there is more than can be done. Luckily, using Legato and the GoFiler Command Line API you have plenty of tools to help you on your way of improving your workflow. Combine these tools with batch files or Powershell and the Windows task scheduler for even more automation! These tools allow you to build off of previous functionality to improve the lives of everyone who uses the software in your environment.
Joshua Kwiatkowski is a developer at Novaworks, primarily working on Novaworks’ cloud-based solution, GoFiler Online. He is a graduate of the Rochester Institute of Technology with a Bachelor of Science degree in Game Design and Development. He has been with the company since 2013. |
Additional Resources
Novaworks’ Legato Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato