Exploiting the power of Windows inside a Mathematica application

David Bailey

http://www.dbaileyconsultancy.co.uk

Normal Windows applications open directly from the desktop, and make Windows recognise their data files as belonging to them. For example, .DOC files belong to a word processor application, and .NB files belong to Mathematica. Files of the appropriate type also have their own icons inside Explorer and on the desktop. This  feature of Windows is tremendously powerful, both because it offers easy access to data, and because data can be usefully embedded in other software - such as XMIND or in HTML. Applications that behave like other Windows software, are also much more acceptable to users unfamiliar with Mathematica.

This talk will describe how to create an application that responds in the same way, without writing part of that application in another language, and will be based on my Super Widget Package, which is available free from my website. It will be illustrated using Hans-Gerlach Woudboer’s “Rapid Business Modeling” software (http://www.rapidbusinessmodeling.com).

Introduction

This talk is about Mathematica running under Windows (32 or 64 bits). We often talk about Mathematica applications as if they were completely analogous to any other Windows application. However, unfortunately they usually enjoy a much lower level of integration with the operating system. If you use most Windows Applications e.g. LibreOffice, or Firefox, or indeed Mathematica itself, they are well integrated into Windows. In Particular:

•  Windows applications are usually started from their own icon on the desktop.

• Windows applications are organised around data files, rather than the applications that process them. This means that users of Libre Office (for example) typically open a folder containing files with a particular suffix (e.g. .DOC or .XLS) and open them with a double click. Behind the scenes, “opening a file” consists of starting the appropriate application if necessary, and passing the file to the application for it to open and display as appropriate, but this is ordinarily of no more interest to the user, than would be a list of block numbers on the disk where his/her data is actually stored!

• Windows applications use some standard GUI conventions that are difficult to copy exactly in a Mathematica notebook.

• Normally, an application gives little or no hint as to the underlying computer language that was used to create it.

While these matters may seem trivial, they do impede the take up of Mathematica applications by people who have no interest in maths or computer programming. I would also argue that the conventional Windows approach to organising data files is so powerful, that many serious applications should exploit this mechanism.

A variety of fairly general software environments (such as web browsers) exploit this mechanism to enable data to be opened easily from within their applications:

<html>
<body>
<H3> Starting programs from HTML</H3>
This illustrated how data sets can be linked into a narative composed in HTML (typically stored
locally rather than on the web).
<a href="file://C:\maths\Consultancy\HansGerlachWoodboer\CalculatorFiles\evr.rbm"> A data file</a>
</body>
</html>

I have discussed the latter two points at previous conferences, so this paper focuses on the issue of making a Mathematica application appear data oriented.

Data orientation the hard way

When a Windows Application (or maybe its installer) registers that it processes a particular data type (i.e. files with a particular suffix, such as .DOC), it does so by storing the following information in the registry:

•   A command that should be used to open the relevant files (where %1 is used as a placeholder for the actual data file path).

•   An icon associated with data of that particular type. For example, Mathematica supplies an icon for files with the NB suffix:

•   A textual description of the data type, to be displayed when the user hovers over the corresponding icon.

This information remains stored even after the application has terminated, ready for use when the user tries to open one of his data files. Remember, when a user comes to open a file, the corresponding application may not be running.

Clearly, one way to achieve this functionality for a Mathematica application, would be to write a GUI front end for the code, in a language such as Java or C, and let it register the file types as belonging to it. Such a program would then open a link to MathKernel and use Mathematica as an invisible calculation engine.

•  From the above diagram, you can see that much of the code ends up being written in a language other than Mathematica.

Accessing the Windows Registry inside Mathematica code

•  Although in what follows, the necessary registry changes are performed automatically inside the Super Widget Package (SWP), the relevant functions exist inside Developer` context, and can be used by any Mathematica program running under Windows, although they are not documented:

?Developer`*Registry*

•  Here are some sample calls to these functions, which are extremely easy to use:

Create a key if it doesn’t already exist

Developer`CreateRegistryKey["HKEY_CURRENT_USER\\Software\\SuperWidgetPackage"]

Write values into one or more keys, name the key Null to reference the default value

Developer`WriteRegistryKeyValues["HKEY_CURRENT_USER\\Software\\SuperWidgetPackage",{
         "SWPCommandFile"->command˘file}]

Read back a set of keys. Note that these are returned in a form suitable for use in ReplaceAll.

Developer`ReadRegistryKeyValues["HKEY_CURRENT_USER\\Software\\SuperWidgetPackage"]

Remove key values

Developer`RemoveRegistryKeyValues[
      "HKEY_CURRENT_USER\\Software\\SuperWidgetPackage",{"SWPCommandFile"}
   ]

•  Obviously, these functions only work in a suitable environment (32-bit or 64-bit Windows, or Wine).

Data orientation using the Super Widget Package

•  Using the Super Widget Package (SWP), everything can be written in Mathematica code, and the registration process is performed with one call to Install˘MathLauncher˘Application for each type of data to be registered (e.g. .RBM and .FLOW).

Install˘MathLauncher˘Application["c:\\prog\\RBMCalculator.m",
      ".rbm","RBMCalculatorDataFile",
      "RBMCalculator data file",
      "c:\\\Data\\rbmdata.ico",
      "SplashScreen"->"c:\\Data\\SplashRapidBusinessModeling.jpg",
      "UseFrontEnd"->False];

•  If the GUI is created using the SWP, or using the Front End, all the code for the application is written in Mathematica.

•  Because the names of the splash screen and Mathematica .m files are stored in the registry indexed by file suffix type, this scheme can potentially cater for multiple data types (with different file suffices) and multiple Mathematica applications.

Mathematica applications started using this scheme

•  Nothing in the SWP, ‘knows’ what it means to open a data file of a specific type. However, the variable MathLauncherSuppliedOpen is set to the full path name of the data file that initiated the process.

•  If ValueQ[MathLauncherSuppliedOpen] is False, it can be assumed that the program was started conventionally

•  Typically, an application may have more than one kind of data, for example, Rapid Business Modelling processes two types of data, .RBM and .FLOW files. However, it is often convenient to register one extra data type – say .RBMAPP – that represents the process of starting the application without a specific initial data set.

•  Since a program can easily extract the suffix of a file name, it can use it to determine the type of processing required:

ToUpperCase[FileExtension["c:\\maths\\something.nb"]]

(Remember that Windows file names are case insensitive, so tests should be made after forcing the case.)

•  The .RBMAPP doesn’t open any file, it just starts the application.

Using multiple data files

If a user opens several data files, one after another, the files are normally passed to one instance of the corresponding application. Thus if you open two .NB files, they both end up in one copy of Mathematica.

•   Once again, this functionality can be enormously useful to a user. For example, data files may get combined in a variety of ways, but this only works if the data is loaded into one copy of the application. In addition, each separate copy of an application requires a separate kernel - so it is easy to exceed the license limit.

•  Obviously an application that is going to receive additional data, must be able to respond in some way. Assuming it creates a GUI interface, there is a natural point when the program is idling awaiting further user activity, when it can respond to such a request.

•  A program with a SWP GUI calls the following function:

Set˘Command˘File[commandFile]

Where commandFile is the full path name of a file that will be used whenever a user double clicks a data icon on the desktop.

•   It then supplies a definition for the function SuperWidgetPackage`MathLauncher˘Open[file_] which will be called with the full path name of any additional data file that the user chooses to open. This call will be made when the GUI is idling, and so will not preempt the application code (a common source of instability).

•  Checks are made to ensure the application is already started, and that it has executed the above call to prepare it to accept additional commands.

•  Note that the SWP can operate an Multiple Document Interface (MDI) analogous to (say) Microsoft Word, in which several files coexist on one desktop.

Starting in the Front End

•  The Install˘MathLauncher˘Application takes an option, “UseFrontEnd”, which when set to True, will lanch a data set into the Front End. From the user’s point of view, this works in the same way as launching into the kernel, but it required a trick to persuade the FrontEnd to start running a .m file without any action on the part of the user.

•  The MathLauncher program sets some information into registry keys, and starts a special notebook file (part of the SWP) which contains Dynamic code which closes itself down and performs a Get on the application .m file. After this step, the process proceeds as above, but it can make full use of the Front End.

•  Creating a notebook that contains Dynamic code that immediately closes itself can be rather tricky! I solved this by making the dynamic code dependent on the variable EditingFrontEndLauncher having no value. This allowed me to edit this notebook in the ordinary way. This notebook can be found inside the SWP: FrontEndLauncher.nb, and may be adaptable to other situations in which a notebook is required to start executing immediately.