Skip to content

Exec_ec

MaartenHilferink edited this page Jun 25, 2026 · 21 revisions

File, Folder and Read functions exec(ute)_ec(errorcode)

syntax

  • exec_ec(command line)
  • exec_ec(command line, current folder path)
  • exec_ec(application name, command line, current folder path)

definition

executes the command line argument and returns it's ExitCode,

It does so by calling CreateProcessA(application name, command line, NULL, NULL, TURE, 0, NULL, NULL, zeroes, zeroes) where application name is NULL when not specified, in which case the application to start is derived from the command line. Once started, command line is what the child process will see when calling GetCommandLine(). See also: Environment.cpp.

When no current folder path is specified, the current folder is inherited from the GeoDms process, which usually is set to the project folder of the last loaded configuration.

You can use such result in the construction of a storage name of a data source which guarantees that it will only be known after completion of that process.

applies to

example

This example shows how to use the exec_ec function to make a list of files in a folder and store the resulting list in a text file, that can be used later in the process to read all files from the folder.

The CanGenerate parameter can be used in your expression to process all files, making sure the list of files or an error code is generated first.

container folderinfo
{
  container impl
  {
     parameter<string> FileNameDirInfo := '%LocalDataProjDir%/dirinfo_' + date +'.str';
     parameter<string> DirCmdOrg       := Expand(., 'Dir '+ XmlDir +'/*.xml > ' + FileNameDirInfo);
     parameter<string> DirCmd          := Replace(DirCmdOrg, '/', '\\') + ' /B';
   }

   parameter<uint32> writeFileList     := 
      exec_ec(Expand(., '%env:ComSpec%'), '/c ' + impl/DirCmd, Expand(., '%LocalDataProjDir%'));
   parameter<bool>   CanGenerate       := writeFileList== 0;
}
container wait_for_exec_ec
{
    parameter<Int32> exitcode := exec_ec(
        "python",
        "C:/path/to/script.py --output C:/path/to/output.csv"
    );
    unit<uint32> output
        StorageName   = = "C:/path/to/output" + String(exitcode - exitcode) + ".csv"
        StorageType   = "gdal.vect"
        StorageReadOnly = "True"
    {
        attribute<String> indicator_A;
    }
}

The term String(exitcode - exitcode) always evaluates to the string "0", so it does not change the resulting file name. Its only purpose is to make the StorageName depend on exitcode: because the storage name can only be determined after exitcode is known, the GeoDMS first runs the exec_ec process (the Python script) and only then opens output and reads it. This guarantees the script has finished before its output is read.

running a Python script and reading its output

This same mechanism is used to let the GeoDMS write an input file, run a Python script on it, and read the script's output back — all triggered automatically the moment the output is requested. The chain is:

  1. write the input data, e.g. as a parquet file (typed and fast for exchange with Python, see parquet);
  2. run the script with exec_ec, capturing its ExitCode;
  3. read the output, with the ExitCode woven into the output StorageName so the read waits for step 2.
container run_python
{
   // 1. write the input the script reads (StorageReadOnly = "False")
   unit<uint32> input := src/objecten
       StorageName     = "%LocalDataProjDir%/Python/temp/input.parquet"
       StorageType     = "gdalwrite.vect"
       StorageReadOnly = "False"
   {
       attribute<uint32>  id          := src/objecten/id;
       attribute<float32> oppervlakte := src/objecten/oppervlakte;
   }

   // 2. run the script; PropValue forces the input above to be written first
   parameter<string> inputWritten := PropValue(input, 'StorageName');
   parameter<int32>  exitcode     :=
       exec_ec("python", '"%LocalDataProjDir%/Python/script.py" "' + inputWritten + '"');

   // 3. read the output; the ExitCode in the StorageName makes the read wait for step 2
   unit<uint32> output
       StorageName     = = '"%LocalDataProjDir%/Python/temp/output' + String(exitcode - exitcode) + '.parquet"'
       StorageType     = "gdal.vect"
       StorageReadOnly = "True"
   {
       attribute<string> result;
   }
}

See parquet for how to relate the read output domain to an already configured domain.

see also

Clone this wiki locally