userDefFunc()

Calls C++ functions.

Synopsis

int userDefFunc(string libName, string fctName, dyn_anytype in, dyn_anytype &out);

Parameters

Parameter Description
libName Name of SHL / DLL library to load
fctName Name of the function to call
in Input parameter
out Return parameter (read/write)

Return value

In the event of error 0, otherwise the function value of the defined function.

Errors

If errors occur when loading the SHL/DLL, the function userDefFunc returns the function value 0 (zero) and a message is logged in the WinCC OA LogViewer.

The function value of the defined function must not be 0!

The expressions <fctName>, <libName> and <error description> ; are replaced by the respective values.

All errors in user-defined functions can have a direct negative effect on the stability of the control manager and must thus be very carefully coded.

When generating tooltips for user-defined functions, WinCC OA does not consider whether a parameter is optional or not. This means that no square brackets will be shown for optional parameters.

Description

The user can call self-coded, powerful compiled C++ functions loaded from Shared Libraries (Linux) or Dynamic Link Libraries (Windows).

The user-defined function must follow a predefined syntax:

int userFunc (const DynVar &in, DynVar &out);

Parameter Description
in Input parameter (from userDefFunc)
out Output parameter (from userDefFunc)

This interface must be observed, otherwise this function cannot be called (only functions with this interface are found in the SHL/DLL). Inside the function, the user has all options with the following restrictions:

These user-defined functions need classes of the Libs/Basics and must thus be based on the API.

The user may only use functions from the library "libBasics", i.e.: API functions such as dpSet, dpGet, ... are NOT available.

The SHL/DLL must be created with the same computer as the WinCC OA Manager.

Also, note that the calling CTRL manager is blocked while user-defined functions are running. Thus, they should be kept as short as possible.

The function value of the user-defined function userFunc is passed to the CTRL function userDefFunc and can be used in the control script. If, however, errors occur when calling functions (for example, if the SHL/DLL is not found), userDefFunc returns 0 (zero) to indicate the error. Thus, user-defined functions must not use function value 0!

To load a SHL/DLL, that is located inside the project directory, the function getPath must be used when calling userdefFunc, otherwise the SHL/DLL will only be searched inside the installation directory. An example function call using getPath: userDefFunc(getPath(BIN_REL_PATH, "mylib.dll"), ...)

Example

#include <iostream.h>
 #include <DynVar.hxx>
 #include <AnyTypeVar.hxx>
 #include <IntegerVar.hxx>
 #include <FloatVar.hxx>
 #if defined(_WIN32)
 # define WCCOA_EXPORT __declspec(dllexport)
 #else
 # define WCCOA_EXPORT
 #endif /* Example 1testFct multiplies integer from parameter <in> by 5 and returns the result in the parameter <out> If successful, the function returns 1, -1 if the parameter <in> is not integer type, -2 if the parameter <out> is not integer type, and -3 if both parameters are not integer type. WARNING: This function will crash if <in> and <out> are the correct type but do not contain any values. In a production version of this function you must also catch these errors so that the overall system remains stable!! Call testFct from the Ctrl */
main()
{
int retVal;
dyn_int in, out;
dyn_dyn_int tab;
in = makeDynInt(5);
out = makeDynInt(0); // required because of REF1
retVal = userDefFunc("testDLL", "testFct", in, out);
 DebugN("retVal=",retVal,", in=",in[1],", out=",out[1]);
}
// =
WCCOA_EXPORT int testFct(
const DynVar &in, // Input parameter: first multiplicand
DynVar &out) // Output parameter: Result
{
int rc = 0; // Function error code
IntegerVar *i; // Integer value of first parameter
IntegerVar *o; // Integer value of second parameter
// Parameter checks ...............................
// The array contains elements of integer type
if (in.getType() != INTEGER_VAR)
rc -= 1;
if (out.getType() != INTEGER_VAR)
rc -= 2;
// ..... Processing ......................................
if (rc == 0)
{
i = (IntegerVar *)in.getFirstVar();
o = (IntegerVar *)out.getFirstVar();
// REF1 In order to overwrite out
// it needs to be created.
 o->setValue(i->getValue() * 5);
rc = 1;
}
return (rc);
}
 //
// Example 2
 //
// Call FctInt3In2Out from the Ctrl
/*
main()
{
int retVal;
dyn_int in, out;
in = makeDynInt(2, 3, 4);
retVal = userDefFunc("testDLL","FctInt3In2Out", in, out);
 DebugN("retVal=",retVal,", in=",in[1], in[2],
in[3],",out=",out[1], out[2]);
}
 Output:----------------
["retVal="][1][", in="][2][3][4][", out="][24][9]
*/
//
static int checkParameter(Variable *in, int paramNr)
{
if (in == 0) // Less than 3 parameters
{
cerr << "Parameter " << paramNr << " does not exist"
<< endl;
return(-(paramNr * 2 + 1));
}
if (in->isA() != INTEGER_VAR) // Is the element integer
{
cerr << "Parameter " << paramNr << " is not type
IntegerVar" << endl;
return(-(paramNr * 2 + 2));
}
return(0);
}
WCCOA_EXPORT int FctInt3In2Out(
const DynVar &in, // Input parameter: first multiplicand
DynVar &out) // Output parameter: Result
{
int rc = 0; // Errorcode of function
IntegerVar *in1; // Integer values of in parameter
IntegerVar *in2;
IntegerVar *in3;
IntegerVar *o1; // Integer value of Out parameter
IntegerVar *o2;
// ..... Parameter checks ....................
// The array contains elements of integer type
if (in.getType() != INTEGER_VAR)
{
cerr << "Input parameters are not integer type" << endl;
return(-1);
}
if (out.getType() != INTEGER_VAR)
{
cerr << "Output parameters are not integer type" << endl;
return(-2);
}
if (rc == 0)
{
Variable *var = in.getFirstVar();
if ((rc = checkParameter(var, 1)) < 0) return(rc);
in1 = (IntegerVar *)var;
var = in.getNextVar();
if ((rc = checkParameter(var, 2)) < 0) return(rc);
in2 = (IntegerVar *)var;
var = in.getNextVar();
if ((rc = checkParameter(var, 3)) < 0) return(rc);
in3 = (IntegerVar *)var;
}
// ..... Processing ......................................
o1 = new IntegerVar;
// CTRL releases variables
o2 = new IntegerVar;
// on release of out
// ..... Write calculation to Output variables .........
 o1->setValue(in1->getValue() * in2->getValue() *
in3->getValue());
 o2->setValue(in1->getValue() + in2->getValue() +
in3->getValue());
// ..... Return values ...................................
out.append(o1);
out.append(o2);
return (1);
}
// Example 3
// Call FctIntFloatInOut from the Ctrl
main()
{
int retVal;
int inInt;
float inFloat;
dyn_anytype in, out;
// Allows you to pass variables of
// different types.
inInt = 10;
inFloat = 0.7;
in[1] = inInt;
in[2] = inFloat;
retVal = userDefFunc("testDLL","FctIntFloatInOut", in, out);
 DebugN("retVal=",retVal,", in=",in[1], in[2],",
out=",out[1], =
out[2]);
}
// Result Output: ----------------
["retVal="][1][", in="][10][0.7][", out="][30][2.1]
*/
//
template <class VAR> int checkParameter(Variable *in, int paramNr, VAR &res)
{
if (in == 0) // Less than 3 parameters
{
cerr << "Parameter " << paramNr << " does not exist"
<< endl;
return(-(paramNr * 3 + 1));
}
if (in->isA() != ANYTYPE_VAR) // Is the element //really an anytype
{
cerr << "Parameter " << paramNr << " notof type AnyTypeVar" << endl;
return(-(paramNr * 3 + 2));
}
// NB:there are also empty anytypes
Variable *var = ((AnyTypeVar *)in)->getVar();
if ((var == 0 ) ||
// Does the anytype have a variable stored
(var->isA() != res.isA() ))
// Is the variable of the desired type
{
cerr << "Parameter " << paramNr << " is not of the expected type" << endl;
return(-(paramNr * 3 + 3));
}
res = *var;
return(0);
}
WCCOA_EXPORT int FctIntFloatInOut(
const DynVar &in, // Input parameter
DynVar &out) // Output parameter
{
int rc = 0; // Function error code
IntegerVar in1; // Integer values in parameter
FloatVar in2; // Float value in parameter
IntegerVar *o1; // Integer value out parameter
FloatVar *o2; // Float value out parameter
// ..... Parameter checks ..............................
// The array contains elements of anytpe type
if (in.getType() != ANYTYPE_VAR)
{
cerr << "Input parameters are not of type anytype" << endl;
return(-1);
}
if (out.getType() != ANYTYPE_VAR)
{
cerr<<"Output parameters are not of type anytype"<< endl;
return(-2);
}
if (rc == 0)
{
// Get integer var from array
Variable *var = in.getFirstVar();
if ((rc = checkParameter(var, 1, in1)) < 0) return(rc);
// Get float var from array
var = in.getNextVar();
if ((rc = checkParameter(var, 2, in2)) < 0) return(rc); }
// ..... Processing .....................................
o1 = new IntegerVar; // CTRL releases variables
o2 = new FloatVar; // on release of out
// ..... Write calculation to Output variables .........
 o1->setValue(in1.getValue() * 3 );
 o2->setValue(in2.getValue() * 3.0);
// ..... Return values .................................
 out.append(AnyTypeVar(o1));
// Array only contains variables of one type
 out.append(AnyTypeVar(o2));
// Thus, hide variable in an anytpe
return (1);
}
}

Assignment

Optional indication of a CTRL library in which the function is contained.

Availability

CTRL