Chapters

  1. Introduction
  2. Structure
  3. Packaging
  4. Logging
  5. Configuration
  6. Debugging EXEs
  7. Handling errors
  8. Testing
  9. Documentation
  10. Make
  11. Providing help
  12. Scheduled Tasks
  13. Windows Services
  14. Windows Event Log
  15. Windows Registry
  16. Creating SetUp.exe
  17. Regular Expressions
  18. Acre
  19. GUI
  20. Git

Appendices

  1. Windows environment vars
  2. User commands
  3. aplcores & WS integrity
  4. Development environment
  5. Special characters

Misc

Now we will make some adjustments to prepare MyApp for being packaged as an EXE. It will run from the command line and it will run ‘headless’ – without a user interface (UI).

Copy all files in z:\code\v02\ to z:\code\v03\. Alternatively you can download version 3 from https://cookbook.dyalog.com.

In a runtime interpreter or an EXE, there is no APL session, and output to the session which would have been visible in a development system will simply disappear.

Information

Note that output assigned to or does not stop the runtime executable.

However, when the result of a function is neither consumed by another function nor assigned to a variable then you will see the message “This Dyalog APL runtime application has attempted to use the APL session and therefore be closed.”, and that will be the end of it.

If we want to see this output, we need to write it to a log file. But how do we find out where we need to make changes? We recommend you think about this from the start, and ensure that all intentional output goes through a log function, or at least use an explicit ⎕← so that output can easily be identified in the source.

Unwanted output to the session

What can you do if you have output appearing in the session and you don’t know where in your application it is being generated? The easiest way is to associate a callback function with the SessionPrint event as in:

   '⎕se' ⎕WS 'Event' 'SessionPrint' '#.Catch'
   #.⎕FX ↑'what Catch m'  ':If 0∊⍴what' '. ⍝ !' ':Else' '⎕←what' ':Endif'
   ⎕FX 'test arg'  '⎕←arg'
   test 1 2 3
⍎SYNTAX ERROR
Catch[2] . ⍝ !

You can even use this to investigate what is about to be written to the session (the left argument of Catch) and make the function stop when it reaches the output you are looking for. In the above example we check for anything that’s empty.

Notes:

  • Avoid the ⎕se.onSessionPrint←'#.Catch' syntax with ⎕SE; just stick with ⎕WS as in the above example.
  • Remember to clear the stack after Catch crashed. If you don’t, and instead call test again, it will behave as if there were no handler associated with the SessionPrint event.

TxtToCsv has a shy result, so it won't write its result to the session. That’s fine.

TxtToCsv needs an argument. The EXE we are about to create must fetch it from the command line. We’ll give MyApp a function StartFromCmdLine.

We will also introduce SetLX: the last line of the DYAPP will run it to set ⎕LX:

Target #
Load Constants
Load Utilities
Load MyApp
Run #.MyApp.SetLX ⍬

In MyApp.dyalog:

:Namespace MyApp

(⎕IO ⎕ML ⎕WX ⎕PP ⎕DIV)←1 1 3 15 1

    ∇r←Version
    ⍝ * 1.0.0
    ⍝   * Runs as a stand-alone EXE and takes parameters from the command line.
      r←(⍕⎕THIS) '1.0.0' 'YYYY-MM-DD'
    ∇
    ...
    ⍝ === VARIABLES ===

    Accents←'ÁÂÃÀÄÅÇÐÈÊËÉÌÍÎÏÑÒÓÔÕÖØÙÚÛÜÝ' 'AAAAAACDEEEEIIIINOOOOOOUUUUY'

⍝ === End of variables definition ===

      CountLetters←{
          {⍺(≢⍵)}⌸⎕A{⍵⌿⍨⍵∊⍺}Accents map toUppercase ⍵
      }
    ...
    ∇ {r}←SetLX dummy
    ⍝ Set Latent Expression (needed in order to export workspace as EXE)
     #.⎕IO←1 ⋄ #.⎕ML←1 ⋄ #.⎕WX←3 ⋄ #.⎕PP←15 ⋄ #.⎕DIV←1
     r←⍬
     ⎕LX←'#.MyApp.StartFromCmdLine #.MyApp.GetCommandLineArgs ⍬'
    ∇

    ∇ {r}←StartFromCmdLine arg
    ⍝ Run the application; arg = usually command line parameters .
       r←⍬
       r←TxtToCsv arg~''''
    ∇

    ∇ r←GetCommandLineArgs dummy
       r←⊃¯1↑1↓2 ⎕NQ'.' 'GetCommandLineArgs' ⍝ Take the last one
    ∇

:EndNamespace

Changes are emphasised.

Now MyApp is ready to be run from the Windows command line, with the name of the file to be processed following the command name.

Notes:

Warning

Inheriting system variables

A common source of confusion is code that relies on system variables having expected values. Your preferred values for those system variables are set in the Dyalog configuration.

Whenever you execute then, say, #.⎕NS '' you can expect the resulting namespace to inherit those settings from the hosting namespace. That’s fine.

But if you send your WS elsewhere then somebody with different values in their Dyalog configuration might load and run your WS. In this environment #.⎕NS '' creates a namespace with different values for system variables: a recipe for disaster.

We’re now nearly ready to export the first version of MyApp as an EXE.

  1. Double-click the DYAPP to create the WS.
  2. From the File menu pick Export.
  3. Pick Z:\code\v03 as the destination folder [1].
  4. From the list Save as type pick Standalone Executable.
  5. Set the File name as MyApp.
  6. Check the Runtime application checkbox.
  7. Clear the Console application checkbox.
  8. Click Save.

You should see a message: File Z:\code\v03\MyApp.exe successfully created. This occasionally (rarely) fails for no obvious reason. If it does fail just try again and you should be fine.

If it keeps failing then the by far most common reason is that the EXE is running – you cannot replace an EXE while it is running.

Information

Although you cannot replace a running EXE what you can do is to rename it; that is possible. You can then create a new EXE with the original name.

In case you wonder what a “Console application” is:

Note that it catches the return code and assigns it to the environment variable “ERRORLEVEL” in any case.

Note that you cannot really debug a console application with Ride; for details see the Debugging a stand-alone EXE chapter.

If you do not check Console application, the program is started as a separate process and you cannot catch the return code.

We therefore recommend you clear the Console application checkbox unless you have a good reason to do otherwise.

Tip

Use the Version button to bind to the EXE information about the application, author, version, copyright and so on. These pieces of information will show in the Properties/Details tab of the resulting EXE.

Note that to use the cursor keys or Home or End within a cell the Version dialog box requires you to enter ‘in-cell’ mode by pressing F2.

Tip

You could specify an icon file to replace the Dyalog icon with your own one.

Let’s run it. From a command line:

Z:\code\v03\MyApp.exe texts\en

Looking in Windows Explorer at Z:\texts\en.csv, we see its timestamp just changed. Our EXE works!


Footnotes

  1. Note that in the Dyalog Cookbook the words folder and directory are used interchangeably.