Skip to main content

Acumatica Scripting Language

  • August 16, 2025
  • 5 replies
  • 121 views

JSpikowski
Jr Varsity II
Forum|alt.badge.img

ScriptBasic was created as an embedded scripting engine. The console interpreter and web server are examples of using the ScriptBasic API. C# is able to call C functions. The host language can get /set variables and call functions.

The script I wrote to get tenant names is good example how you could use ScriptBasic for missing functionality.

ScriptBasic is open source with a MIT Common license. It is commercially used primarily by industrial controllers as its scripting engine.

ScriptBasic runs on Windows (32/64 bit) and Linux.

using System;
using System.Runtime.InteropServices;

class Program
{
// Import the Add function from the C DLL
[DllImport("Example.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);

static void Main()
{
int result = Add(5, 3);
Console.WriteLine($"Result: {result}"); // Output: Result: 8
}
}

This C example is calling the ScriptBasic DLL (libcriba.dll) to execute a script. All of the ScriptBasic extension modules are available from within the called embedded script.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "scriba.h"

__declspec(dllexport) int sb(char * ScriptName, char * ScriptArgs)
{
pSbProgram pProgram;

pProgram = scriba_new(malloc,free);
scriba_LoadConfiguration(pProgram, "C:\\Windows\\SCRIBA.INI");
scriba_SetFileName(pProgram, ScriptName);
scriba_LoadSourceProgram(pProgram);
scriba_Run(pProgram, ScriptArgs);

scriba_destroy(pProgram);

return(0);
}

All of the examples I have posted could be run as a call to ScriptBasic from within your C# program.

 

5 replies

JSpikowski
Jr Varsity II
Forum|alt.badge.img
  • Author
  • Jr Varsity II
  • August 16, 2025

I wrote a ScriptBasic C extension module (SBT) that embeds ScriptBasic in ScriptBasic with the ability to run the script as a thread. This is a great way to play with your embedded scripts before implementing them in your C# code.

When running your scripts as a thread, you can IMPORT the MT extention module giving you shared variables between your host and the threads it created as a sub-process.

 

 

 

 


JSpikowski
Jr Varsity II
Forum|alt.badge.img
  • Author
  • Jr Varsity II
  • August 16, 2025

This is an example of using the SBT extension module I mentioned in the previous post. This shows calling a function and setting / getting variables.

  • Script is a text string being passed
  • Script is loaded but not run
  • Call un-run script function prtvars() passing arguments
  • Return function results
  • Run script initializing variables A,B and C
  • Set A,B and C variables from host
  • Call prtvars() function again using variables set in previous step
' SBT Demo

IMPORT sbt.sbi

sb_code = """
FUNCTION prtvars(a, b, c)
PRINT a,"\\n"
PRINT FORMAT("%g\\n", b)
PRINT c,"\\n"
prtvars = "Function Return"
END FUNCTION

a = 0
b = 0
c = ""
"""

sb = SBT::SB_New()
SBT::SB_Configure(sb, "C:/Windows/SCRIBA.INI")
SBT::SB_Loadstr(sb, sb_code)
SBT::SB_NoRun(sb)
' Call function before running script
funcrtn = SBT::SB_CallSubArgs(sb,"main::prtvars", 123, 1.23, "One, Two, Three")
PRINT funcrtn,"\n"
' Run script initializing globals
rtn = SBT::SB_Run(sb, "")
' Assign variables values
SBT::SB_SetInt(sb, "main::a", 321)
SBT::SB_SetDbl(sb, "main::b", 32.1)
SBT::SB_SetStr(sb, "main::c", "Three,Two,One" & CHR(0))
' Call function again with variables assigned in the previous step
SBT::SB_CallSubArgs(sb, "main::prtvars", _
SBT::SB_GetVar(sb, "main::a"), _
SBT::SB_GetVar(sb, "main::b"), _
SBT::SB_GetVar(sb, "main::c"))

SBT::SB_Destroy(sb)

Output

C:\Acumatica>sbc sbt_demo.sb
123
1.23
One, Two, Three
Function Return
321
32.1
Three,Two,One

C:\Acumatica>


JSpikowski
Jr Varsity II
Forum|alt.badge.img
  • Author
  • Jr Varsity II
  • August 17, 2025

This SBT example runs a script as a thread and uses MT to communicate with it. Both scripts (Main and Thread) run a FOR/NEXT loop simultaneously.

You are able to call functions and get / set variables with threads as well.

' SBT Main

IMPORT mt.sbi
IMPORT sbt.sbi

SBT::SB_ThreadStart("sbt_thread.sb", "","C:/Windows/SCRIBA.INI")

FOR x = 1 TO 10
PRINT "M:",x,"\n"
SBT::sb_msSleep(20)
NEXT

SBT::SB_msSleep(1000)

PRINT "Thread ",mt::GetVariable("thread_status"),"\n"
' SBT Thread

IMPORT mt.sbi
IMPORT sbt.sbi

FOR x = 1 TO 10
PRINT "T:",x,"\n"
SBT::SB_msSleep(20)
NEXT

mt::SetVariable "thread_status","Completed"

SBT::SB_ThreadEnd

Output

C:\Acumatica>sbc sbt_main.sb
T:1
M:1
T:2
M:2
T:3
M:3
T:4
M:4
T:5
M:5
T:6
M:6
T:7
M:7
M:8
T:8
T:9
M:9
T:10
M:10
Thread Completed

C:\Acumatica>


JSpikowski
Jr Varsity II
Forum|alt.badge.img
  • Author
  • Jr Varsity II
  • August 17, 2025

Your C# program could load a set of FUNCTION() / SUB() routines along with any variables you want to preset and call the functions when you need them. Before you close your C# program, you would want to Destroy() the ScriptBasic object and free up its memory.

You could use ScriptBasic's JSON to associative array feature and return a standard JSON string. This makes working with JSON data much easier. You can copy segments of the array and build a new request before returning it to Acumatica.


JSpikowski
Jr Varsity II
Forum|alt.badge.img
  • Author
  • Jr Varsity II
  • August 17, 2025

If there was interest in Acumatica having a scripting engine, the way to go would make it a common object you can include in your project for its use.

I think Acumatica should offer scripting as a standard feature.