Implementation Overview

Before you can harness the power of the SCEX calculation engine, you first need to be able to call the function(s) contained in the library from your development language.

Functional Interface

To make use of the SCEX, you will need to import one (and only one!) function from the library into your programming environment. Any programming language which can access functions inside shared libraries on your SCEX platform of choice (current platforms supported include win-32, win-64 and linux-x86.64) and has the appropriate data types necessary to call the xmlcalc_ddp() routine should be able to make use of the SCEX.

The only function exported from the SCEX library that is required for implementation (and hence the only one you need to import) is called xmlcalc_ddp(). Here is the function declaration for xmlcalc_ddp(), in Delphi (object pascal, and the language in which the SCEX is written):

function xmlcalc_ddp(
  xmlIn, xmlOut: PAnsiChar;
  lenIn, lenOut: integer;
  var reqIn, reqOut: integer;
  DataDirPath: PAnsiChar
): integer; stdcall;

Note that for the Linux platforms, the stdcall calling convention is replaced with cdecl.

The variable names are found to the left of the :, with the variable type found to its right. This function uses two types of variables: PAnsiChars and integers. Integers are 32-bits in size, and are signed. PAnsiChars are pointers to ANSI character buffers, and in C are expressed as char *. The var modifier indicates that the reqIn and reqOut variables are being passed by reference instead of by value (like the variables xmlIn, xmlOut, lenIn and lenOut are).

Now, let’s see how to go about importing this function in five different languages: Delphi, Visual C++, C#, vb.net, and Java.

Delphi

As the SCEX DLL is written in the Delphi programming environment, it is to be expected that importing the function into a Delphi application is a fairly simple process.

Place the following function declaration in the interface section of a Delphi unit:

function xmlcalc_ddp(
  xmlIn, xmlOut: PAnsiChar;
  lenIn, lenOut: integer;
  var reqIn, reqOut: integer;
  DataDirPath: PAnsiChar
): integer; stdcall; external 'SCEX.DLL'

In this same unit, place the following code in the interface section. Please note that there is no semicolon at the end of this line, and that the SCEX DLL must reside in the same location as your application for this method to work.

Visual C++

To use the xmlcalc_ddp() routine in your Visual C++ application, you will need to dynamically load the library in your code and get the process address for the xmlcalc_ddp() function in that Library. This is best done in your application’s initialization routines, so that once your application has started the function is ready to accept calls. When you terminate the application, then you free up the dynamically loaded library in your code’s termination routine. The relevant Windows API calls which are used in this process are: LoadLibrary(), GetProcAddress(), and FreeLibrary(). For more information, please see the sample code (installed when you install the SCEX Sample Source Code component during the SCEX installation).

C#

To import that xmlcalc_ddp() function into your C# project from scratch, you will need to use System.Runtime.InteropServices. Furthermore, you will also need to be familiar with the StringBuilder class in System.Text, which is the C# equivalent of a character buffer.

For a complete SCEXWrapper class, please see the sample code (installed when you install the SCEX Sample Source Code component during the SCEX installation).

Java

As of release 2018-07-0 of the SCEX, a Java Native Interface function is included in the SCEX library for all supported platforms, and a Java class which implements the JNI call is provided in the sample source code directory java\Scex.java (note that if you did not install the sample source code during installation, then this file will not be present).

To illustrate the use of the Scex.java class, we have also included a simple Java class (Main.java) which creates an instance of the Scex class, sets up an SCEX XML query, and then calls the SCEX and displays the result code and resulting XML.

Note that when using the JNI interface to the SCEX, you must always specify a fully qualified path name for the DTD file, and you must also always specify the DataDirPath attribute for those XML queries which accept one.

If you wish to modify any aspects of the Scex.java file, please carefully read the comments included in it. The JNI function included in the SCEX DLL expects and requires many different facets of class Scex to be as described, and modifying these will result in a non-functional interface. It is our recommendation that Scex.java be left as is unless you are very familiar with the JNI.

Implementing the xmlcalc_ddp() Function

If you are directly calling the xmlcalc_ddp() function exported from the SCEX DLL (instead of using one of the wrapper classes provided with the sample source code), then the next step is to understand the function’s parameters and return results. If you are using one of the provided wrapper classes, then implementation is a bit easier.

Calling xmlcalc_ddp() Directly

If you wish to directly access the xmlcalc_ddp() function, then there are three facets which you must consider: variable declarations, memory allocation and result interpretation.

Variable Declarations

There are four classifications of variables passed to the xmlcalc() routine: pointers to character buffers, allocated buffer sizes, required buffer sizes, and the default data directory path.

The xmlIn and xmlOut variables are pointers to character buffers which your application has allocated (see Memory Allocation, below). The input buffer xmlIn is filled by your application before calling xmlcalc_ddp(), and its contents represent an XML query sent to the SCEX. The result of the query will be returned in the xmlOut buffer, so long as no errors are encountered (see Result Interpretation, below).

The lenIn and lenOut variables are the lengths of the associated buffers. It is critical that your application correctly set the values of these variables to represent the allocated lengths of the input and output buffers, respectively. By informing the SCEX of the size of the input and output buffers, buffer over-runs and the errors that they cause will be non-existent.

The reqIn and reqOut are return parameters used to indicate the necessary size of the input and output buffers. These two result parameters are very useful when you have not allocated enough space for the input or output buffers, as indicated by a given function result code (see Result Interpretation, below).

Finally, the DataDirPath specifies a default data directory for the SCEX to use if one is not supplied in the XML input. Please see documentation on the DataDirPath attribute in the chapter covering Equal Payment Loans for the meaning of this variable.

Memory Allocation

As noted above, providing a buffer into which both the SCEX and your example can copy xml code is of paramount importance. The exact function calls and variable types that you must vary from language to language. Here are a few samples:

  • Delphi: To allocate memory for the character buffers which will hold the xmlcalc_ddp() input and output, you can use GetMem(buffer, length), where buffer is of type PAnsiChar (a pointer to character) and length is the requested length of the character buffer, in bytes. Once you are done with the character buffers, make sure to free up the memory which was dynamically allocated using the FreeMem(buffer) procedure, where buffer is again a PChar.

  • C, Visual C++: To allocate memory for the input and output buffers in C and Visual C++, use the standard library functions malloc() and free(). See the Visual C++ sample application for an example of how the buffers are dynamically allocated.

  • C#, vb.net: Use the StringBuilder class from System.Text. See sample code for an example of its use (and a more user friendly wrappers around xmlcalc()).

Result Interpretation

After calling xmlcalc_ddp(), you should always check the integer return value to ensure that the call finished successfully, and if it did not, what kind of error occurred. Please see Table 3.1 on page 13 for a comprehensive list of result codes accompanied by a description of each.

Result CodeDescription
0Successful calculation. Results are in xmlOut.
1Not enough input space reserved. More buffer space is required to write the XML inputs. The minimum size required for the input buffer is returned in the reqIn parameter.
2Not enough output space reserved. More buffer space is required to write the XML outputs. The minimum size required for the output buffer is returned in the reqOut parameter.
3XML Output is not well formed. XML output violates at least one rule defining well-formed XML data.
4XML output is not valid.
-1XML input is not well formed. XML input violates at least one rule defining well-formed XML data.
-2XML input is not valid. (See the various query interface chapters for definitions of valid XML input).
-3An exception occurred within the SCEX.

Optional API Functions

Besides the very important xmlcalc_ddp() routine exported from the SCEX, there are other helpful routines which may be of use during development. Each of these routines is described below.

scex_calc_alloc() and scex_calc_free()

The scex_calc_alloc() routine behaves identically to the xmlcalc_ddp() routine, with the exception that the library function will automatically allocate the necessary output buffer. When first calling this routine, ensure that the output buffer is initialized to NULL and the size of the output buffer is set to zero.

Using this function will prevent calling xmlcalc_ddp() twice when the space allocated by the calling application for the output buffer is too small, and thus can effectively cut the calculation speed in half in these instances.

Since the library is allocating the space necessary for the XML output buffer, the library also must be responsible for freeing this allocated space. Thus, there is the associated scex_calc_free() library function.

Note that many of the sample code wrappers provided have been enhanced to use these new routines to ensure maximum performance.

Here are the function declarations for scex_calc_alloc() and scex_calc_free(), in Delphi (object pascal, and the language in which the SCEX is written):

function scex_calc_alloc( InBuff : PAnsiChar;
  var OutBuff : PAnsiChar;
  InBuffSize : integer;
  var OutBuffSize : integer;
  RootPath : PAnsiChar
): integer; stdcall;

function scex_calc_free( var OutBuff : PAnsiChar;
  var OutBuffSize : integer
): integer; stdcall;