Writing Plugins

Simba scripts can be extended with plugins. Plugins are libraries (dll/so/dylib) which can be written in virtually every low-level language.

Note

For 32bit the cdecl calling convention is used for methods plugin related. Otherwise the default systems calling convention is used.


Importing functions

To import functions the following methods must be exported to provide information to Simba.

function GetFunctionInfo(Index: Integer; var Address: Pointer; var Header: PChar): Integer; cdecl;
function GetFunctionCount: Integer; cdecl;

Note

Appending native; to the header cause parameters and result passed in the Lape wrapper format.
This is the preferred way, otherwise libffi is used.

The Lape wrapper format is procedure(const Params: PParamArray; const Result: Pointer)


Importing types

To import types the following methods must be exported to provide information to Simba.

function GetTypeInfo(Index: Integer; var Name: PChar; var Str: PChar): Integer; cdecl;
function GetTypeCount: Integer; cdecl;

Note

These methods are imported before GetFunctionInfo & GetFunctionCount so these types will be available when adding functions.


Importing code

Code can be imported in the script with the following methods exported.

procedure GetCode(var Code: PChar); cdecl;
function GetCodeLength: Integer; cdecl;

RegisterSimbaPlugin

A plugin can export RegisterSimbaPlugin which provides access to various Simba’s infomation & methods.

procedure RegisterSimbaPlugin(Infomation: PSimbaInfomation; Methods: PSimbaMethods); cdecl;

These pointers are provided to these structures:

TSimbaInfomation = packed record
  SimbaVersion: Integer;
  SimbaMajor: Integer;

  FileName: PChar;

  Compiler: Pointer;
end;

TSimbaMethods = packed record
  RunOnMainThread: procedure(Method: TMainThreadMethod; Data: Pointer = nil); cdecl;

  GetMem: function(Size: NativeUInt): Pointer; cdecl;
  FreeMem: function(P: Pointer): NativeUInt; cdecl;
  AllocMem: function(Size: NativeUInt): Pointer; cdecl;
  ReAllocMem: function(var P: Pointer; Size: NativeUInt): Pointer; cdecl;
  MemSize: function(P: Pointer): NativeUInt; cdecl;

  RaiseException: procedure(Message: PChar); cdecl;

  GetTypeInfo: function(Compiler: Pointer; Typ: PChar): Pointer; cdecl;
  GetTypeInfoSize: function(TypeInfo: Pointer): NativeInt; cdecl;
  GetTypeInfoFieldOffset: function(TypeInfo: Pointer; FieldName: PChar): NativeInt; cdecl;

  AllocateRawArray: function(ElementSize, Len: NativeInt): Pointer; cdecl;
  ReAllocateRawArray: procedure(var Arr: Pointer; ElementSize, NewLen: NativeInt); cdecl;

  AllocateArray: function(TypeInfo: Pointer; Len: NativeInt): Pointer; cdecl;
  AllocateString: function(Data: PChar): Pointer; cdecl;
  AllocateUnicodeString: function(Data: PUnicodeChar): Pointer; cdecl;

  SetArrayLength: procedure(TypeInfo: Pointer; var AVar: Pointer; NewLen: NativeInt); cdecl;
  GetArrayLength: function(AVar: Pointer): NativeInt; cdecl;

  ExternalImage_Create: function(AutoResize: Boolean): Pointer; cdecl;
  ExternalImage_SetMemory: procedure(Img: Pointer; Data: PColorBGRA; AWidth, AHeight: Integer); cdecl;
  ExternalImage_Resize: procedure(Img: Pointer; NewWidth, NewHeight: Integer); cdecl;
  ExternalImage_SetUserData: procedure(Img: Pointer; UserData: Pointer); cdecl;
  ExternalImage_GetUserData: function(Img: Pointer): Pointer; cdecl;
end;

See the Example C++ plugin to see how TypeInfo is used to allocate custom records & arrays.

Note

Scripts are not ran on the process main thread so RunOnMainThread is available for creating forms, installing windows hooks that must be executed on the main thread.