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