Writing a Wrapper Module to Call the C Function

The mechanism by which an IMLPlus program calls a C function within a DLL is the DllFunction class. The general procedure for using the DllFunction class is as follows:

  1. Create an object of type DllFunction.
  2. Call the Init method of the DllFunction class. The Init method specifies the filename of the DLL, the name of the function to be called within the DLL, and the number of parameters the function expects.
  3. Specify the type and value of each function parameter by calling the NextArgIs methods of the DllFunction class.
  4. Perform the actual function call by calling one of the Call_ methods of the DllFunction class.

Because of the number of programming statements required to use the DllFunction class, it is usually best to write an IML module to encapsulate access to a C function.

IML Studio is distributed with a sample program that defines a wrapper module that encapsulates access to the example function My_C_Function. The sample program is called Demo_My_C_Function.sx and is stored in the subdirectory

<IMLStudio>\Programs\Samples\User Extensions

where <IMLStudio> is the directory in which you installed IML Studio. The program defines the following wrapper module called My_C_Function:

/* Wrapper module to call the C function "My_C_Function"
   exported from the DLL "My_C_Functions.dll".
   The C function computes the simple product of a scalar with
   a vector: y = c * x
   Module Inputs:
        double c a scalar
        Matrix x an (n x 1) matrix (that is, a column vector)
   Module Outputs:
        returns an (n x 1) matrix y such that y = c * x
*/
start My_C_Function( double c, x );
    declare int nRows = nrow(x);
    declare double[] adY = new double[nRows];

    declare String sPathName; /* location of DLL */
    sPathName = "C:\My_C_Functions\Debug\My_C_Functions.dll";
    declare String sFuncName; /* name of function in DLL */
    sFuncName = "My_C_Function";

    declare DllFunction func = new DllFunction();
    func.Init( sPathName, sFuncName, 4 ); /* 4 parameters */
    func.NextArgIsInt32( nRows );
    func.NextArgIsDouble( c );
    func.NextArgIsDoubleArray( x );
    func.NextArgIsDoubleArray( adY );

    /* call function and get the return value */
    declare int nReturnValue;
    nReturnValue = func.Call_Int32();
    if nReturnValue != 0 then do;
        print "The C function returned an error code.";
        abort;
        end;
    return ( adY );
finish;

The module takes two parameters: a scalar constant c, and a matrix x. An explanation of the module's statements follows:

  1. The module defines an int variable called nRows that specifies the number of rows in the x vector.
  2. The module creates an array of type double to contain the output vector computed by the C function.
  3. The module defines a String object to contain the complete pathname of the DLL containing the C function.
  4. The module defines a String object to contain the name of the C function.
  5. The module creates an object of the DllFunction class.
  6. The module calls the Init method of the DllFunction class and specifies that the C function requires 4 parameters.
  7. The module calls the NextArgIsInt32 method of the DllFunction class to specify that the first function parameter is a 32-bit integer with the value of the nRows variable.
  8. The module calls the NextArgIsDouble method of the DllFunction class to specify that the second function parameter is a double-precision floating-point number with the value of the c variable.
  9. The module calls the NextArgIsDoubleArray method of the DllFunction class to specify that the third function parameter is a pointer to an array of double-precision floating-point numbers. The pointer passed to the C function points to the x variable's data. A numeric matrix variable can be passed to a C function that expects a parameter of type "const double *".
  10. The module calls the NextArgIsDoubleArray method of the DllFunction class to specify that the fourth function parameter is a pointer to an array of double-precision floating-point numbers. The pointer passed to the C function points to the adY variable's data.
  11. The module defines an int variable to hold the return value from the C function.
  12. The module calls the Call_Int32 method of the DllFunction class and assigns the 32-bit integer return value from the C function to the nReturnValue variable.
  13. The module checks the nReturnValue variable to see if the C function returned a non-zero value, which indicates that an error occurred. If an error occurred, the module aborts the program.
  14. The module returns the adY variable as the module's return value. IMLPlus automatically converts the double array data type to the matrix data type returned from all function modules.