PLCopen function blocks
The TwinCAT OPC UA Client offers several options for communicating directly with one or more OPC UA servers from the control logic. On the one hand, there is a TwinCAT I/O device, which offers a simple, mapping-based interface. On the other hand, PLCopen provides standardized function blocks that can be used to initiate a connection with an OPC UA server directly from the PLC logic. The handling of these function blocks is described in more detail below. This article consists of the following sections:
- Workflow
- Determination of the communication parameters
- Establishing a connection
- Reading variables
- Writing variables
- Calling methods
Workflow
The general workflow when using the PLCopen function blocks can be schematically represented as follows:

In the preparation phase, the communication parameters are set up and a connection to the server is established. The desired function is then executed (read, write, method calls), followed by disconnection of the communication connection.
Determination of the communication parameters
In general a graphic OPC UA Client is used to determine the attributes of a node or methods that have to be used together with the PLC function blocks, e.g.:
- NodeID
- NamespaceIndex and corresponding NamespaceURI
- DataType
- MethodNodeID and ObjectNodeID
The following documentation uses the generic OPC UA Client UA Expert as an example. This client can be purchased via the Unified Automation web pages: www.unified-automation.com.
Nodes are characterized by the following three attributes, which form the so-called NodeID:
- NamespaceIndex: The namespace in which the node is located, such as the PLC runtime
- Identifier: Unique identifier of the node within its namespace
- IdentifierType: Type of node: String, Guid and Numeric
These attributes represent the so-called NodeID - the representation of a node on an OPC UA server - and are required by many subsequent function blocks.
With the help of the UA Expert software you can simply determine the attributes of a node by establishing a connection to the OPC UA server and browsing to the desired node. The attributes are then visible in the Attributes panel, e.g.

According to the OPC UA specification, the NamespaceIndex can be a dynamically generated value. Therefore, OPC UA Clients must always use the corresponding namespace URI to resolve the NamespaceIndex before a node handle is detected.
Use the function block UA_GetNamespaceIndex to obtain the NamespaceIndex for a NamespaceURI. The NamespaceURI required for this can be determined with the help of UA Expert by establishing a connection to the OPC UA server and browsing to the NamespaceArray node.

This node contains information about all namespaces registered on the OPC UA Server.
The corresponding namespace URIs are visible in the Attributes panel, for example:

The section above shows an example of a NodeID in which the namespace index is 5. According to the NamespaceArray shown in the figure, the corresponding NamespaceURI is urn://SVENG-NB04/BeckhoffAutomation/Ua/PLC1. This URI can now be used for the function block UA_GetNamespaceIndex. The OPC UA Server ensures that the URI always remains the same, even after a restart.
![]() | Observe the correct NamespaceIndex As the NamespaceIndex shown can change, the NamespaceURI should always be used in combination with the function block UA_GetNamespaceIndex for later use with other function blocks, e.g. UA_Read, UA_Write, to resolve the correct NamespaceIndex. |
DataType
The data type of a node is required in order to see which PLC data type needs to be used in order to assign a read value or write it to a node. With the help of UA Expert you can simply determine the data type of a node by establishing a connection to the OPC UA Server and browsing to the desired node.
The data type is then visible in the Attributes panel, for example:

In this case the data type (DataType) is "Int16". This must be assigned to an equivalent data type in the PLC, e.g. "INT".
MethodNodeID and ObjectNodeID
When calling methods from the OPC UA namespace, two identifiers are required if the method handle is get using the function block UA_MethodGetHandle:
- ObjectNodeID: Identifies the UA object that contains the method.
- MethodNodeID: Identifies the method itself.
With the help of UA Expert you can simply determine both NodeIDs by establishing a connection to the OPC UA server and browsing to the desired method or the desired UA object that contains the method.
Sample Method M_Mul:

The method identifier is then visible in the Attributes panel.

Sample Object fbMathematics:

The object identifier is then visible in the Attributes panel.

Establishing a connection
The following section describes how you use the function block TcX_PLCopen_OpcUa to establish a connection to a local or remote OPC UA server. This connection can then be used to call other functions, such as read or write nodes, or call methods.
The following function blocks are required to establish a connection to an OPC UA server and subsequently interrupt the session: UA_Connect, UA_Disconnect.
![]() | First read the section How to determine communication parameters to better understand certain UA functionalities (e.g. how to determine NodeIdentifiers). |
The function block UA_Connect requires the following information in order to be able to establish a connection to a local or remote OPC UA server:
- Server URL
- Session Connect Information
The Server URL basically consists of a prefix, a host name and a port. The prefix describes the OPC UA transport protocol that should be used for the connection, e.g. "opc.tcp://" for a binary TCP connection (default). The host name or IP address part describes the address information of the OPC UA target server, e.g. "192.168.1.1" or "CX-12345". The port number is the target port of the OPC UA Server, e.g. "4840". The Server URL can then look like this: opc.tcp://CX-12345:4840.
Declaration:
(* Declarations for UA_Connect *)
fbUA_Connect : UA_Connect;
SessionConnectInfo : ST_UASessionConnectInfo;
nConnectionHdl : DWORD;
(* Declarations for UA_Disconnect *)
fbUA_Disconnect : UA_Disconnect;
(* Declarations for state machine and output handling *)
iState : INT;
bDone : BOOL;
bBusy : BOOL;
bError : BOOL;
nErrorID : DWORD;
Implementation:
CASE iState OF
0:
bError := FALSE;
nErrorID := 0;
SessionConnectInfo.tConnectTimeout := T#1M;
SessionConnectInfo.tSessionTimeout := T#1M;
SessionConnectInfo.sApplicationName := "";
SessionConnectInfo.sApplicationUri := "";
SessionConnectInfo.eSecurityMode := eUASecurityMsgMode_None;
SessionConnectInfo.eSecurityPolicyUri := eUASecurityPolicy_None;
SessionConnectInfo.eTransportProfileUri := eUATransportProfileUri_UATcp;
stNodeAddInfo.nIndexRangeCount := nIndexRangeCount;
stNodeAddInfo.stIndexRange := stIndexRange;
iState := iState + 1;
1:
fbUA_Connect(
Execute := TRUE,
ServerURL := "opc.tcp://192.168.1.1:4840",
SessionConnectInfo := SessionConnectInfo,
Timeout := T#5S,
ConnectionHdl => nConnectionHdl);
IF NOT fbUA_Connect.Busy THEN
fbUA_Connect(Execute := FALSE);
IF NOT fbUA_Connect.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_Connect.ErrorID;
nConnectionHdl := 0;
iState := 0;
END_IF
END_IF
2:
fbUA_Disconnect(
Execute := TRUE,
ConnectionHdl := nConnectionHdl);
IF NOT fbUA_Disconnect.Busy THEN
fbUA_Disconnect(Execute := FALSE);
IF NOT fbUA_Disconnect.Error THEN
iState := 0;
ELSE
bError := TRUE;
nErrorID := fbUA_Disconnect.ErrorID;
iState := 0;
nConnectionHdl := 0;
END_IF
END_IF
END_CASE
Reading variables
The following section describes how to use the function blocks TcX_PLCopen_OpcUa to read an OPC UA node from a local or remote OPC UA server. The following function blocks are required to establish a connection to an OPC UA server, read UA nodes and later interrupt the session: UA_Connect, UA_GetNamespaceIndex, UA_NodeGetHandle, UA_Read, UA_NodeReleaseHandle, UA_Disconnect.
The schematic workflow of each TwinCAT OPC UA Client can be categorized into three different phases: Preparation, Work and Cleanup.
The use case described in this section can be visualized as follows:

- The function block UA_Connect requires the following information to establish a connection to a local or remote OPC UA Server (see also How to establish a connection):
- Server URL
- Session Connect Information
- The function block UA_GetNamespaceIndex requires a Connection Handle (from UA_Connect) and a NamespaceURI for resolution to a NamespaceIndex, which is later used by UA_NodeGetHandle to capture a node handle (see also How to determine communication parameters).
- The function block UA_NodeGetHandle requires a Connection Handle (from UA_Connect) and NodeID (from ST_UANodeID) to capture a node handle (see also How to determine communication parameters).
- The function block UA_Read requires a connection handle (from UA_Connect), a node handle (from UA_NodeGetHandle) and a pointer to the target variable (where the read value is to be saved). Make sure that the target variable has the correct data type (see also How to determine communication parameters).
- The function block UA_NodeReleaseHandle requires a connection handle (from UA_Connect) and a node handle (from UA_NodeGetHandle).
Declaration:
(* Declarations for UA_GetNamespaceIndex *)
fbUA_GetNamespaceIndex : UA_GetNamespaceIndex;
nNamespaceIndex : UINT;
(* Declarations for UA_NodeGetHandle *)
fbUA_NodeGetHandle : UA_NodeGetHandle;
NodeID : ST_UANodeID;
nNodeHdl : DWORD;
(* Declarations for UA_Read *)
fbUA_Read : UA_Read;
stIndexRange : ARRAY [1..nMaxIndexRange] OF ST_UAIndexRange;
nIndexRangeCount : UINT;
stNodeAddInfo : ST_UANodeAdditionalInfo;
sNodeIdentifier : STRING(MAX_STRING_LENGTH) := 'MAIN.nCounter';
nReadData : INT;
cbDataRead : UDINT;
(* Declarations for UA_NodeReleaseHandle *)
fbUA_NodeReleaseHandle : UA_NodeReleaseHandle;
Implementation:
CASE iState OF
0:
[...]
2: (* GetNS Index *)
fbUA_GetNamespaceIndex(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NamespaceUri := sNamespaceUri,
NamespaceIndex => nNamespaceIndex
);
IF NOT fbUA_GetNamespaceIndex.Busy THEN
fbUA_GetNamespaceIndex(Execute := FALSE);
IF NOT fbUA_GetNamespaceIndex.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_GetNamespaceIndex.ErrorID;
iState := 6;
END_IF
END_IF
3: (* UA_NodeGetHandle *)
NodeID.eIdentifierType := eUAIdentifierType_String;
NodeID.nNamespaceIndex := nNamespaceIndex;
NodeID.sIdentifier := sNodeIdentifier;
fbUA_NodeGetHandle(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeID := NodeID,
NodeHdl => nNodeHdl);
IF NOT fbUA_NodeGetHandle.Busy THEN
fbUA_NodeGetHandle(Execute := FALSE);
IF NOT fbUA_NodeGetHandle.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_NodeGetHandle.ErrorID;
iState := 6;
END_IF
END_IF
4: (* UA_Read *)
fbUA_Read(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeHdl := nNodeHdl,
cbData := SIZEOF(nReadData),
stNodeAddInfo := stNodeAddInfo,
pVariable := ADR(nReadData));
IF NOT fbUA_Read.Busy THEN
fbUA_Read( Execute := FALSE, cbData_R => cbDataRead);
IF NOT fbUA_Read.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_Read.ErrorID;
iState := 6;
END_IF
END_IF
5: (* Release Node Handle *)
fbUA_NodeReleaseHandle(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeHdl := nNodeHdl);
IF NOT fbUA_NodeReleaseHandle.Busy THEN
fbUA_NodeReleaseHandle(Execute := FALSE);
IF NOT fbUA_NodeReleaseHandle.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_NodeReleaseHandle.ErrorID;
iState := 6;
END_IF
END_IF
6:
[...]
END_CASE
Writing variables
The following section describes how you use the function block TcX_PLCopen_OpcUa to write values in an OPC UA node from a local or remote OPC UA server. The following function blocks are required to establish a connection to an OPC UA server, write UA nodes and subsequently interrupt the session: UA_Connect, UA_GetNamespaceIndex, UA_NodeGetHandle, UA_Write, UA_NodeReleaseHandle, UA_Disconnect.
The schematic workflow of each TwinCAT OPC UA Client can be categorized into three different phases: Preparation, Work and Cleanup.
The use case described in this section can be visualized as follows:

- The function block UA_Connect requires the following information in order to be able to establish a connection to a local or remote OPC UA server (see also How to establish a connection):
- Server URL
- Session Connect Information
- The function block UA_GetNamespaceIndex requires a Connection Handle (from UA_Connect) and a NamespaceURI for resolution to a NamespaceIndex, which is later used by UA_NodeGetHandle to capture a node handle (see also How to determine communication parameters).
- The function block UA_NodeGetHandle requires a Connection Handle (from UA_Connect) and NodeID (from ST_UANodeID) to capture a node handle (see also How to determine communication parameters).
- The function block UA_Write requires a connection handle (from UA_Connect), a node handle (from UA_NodeGetHandle) and a pointer to a variable containing the value that is to be written. Make sure that the target variable has the correct data type (see also How to determine communication parameters).
- The function block UA_NodeReleaseHandle requires a connection handle (from UA_Connect) and a node handle (from UA_NodeGetHandle).
Declaration:
(* Declarations for UA_GetNamespaceIndex *)
fbUA_GetNamespaceIndex : UA_GetNamespaceIndex;
nNamespaceIndex : UINT;
(* Declarations for UA_NodeGetHandle *)
fbUA_NodeGetHandle : UA_NodeGetHandle;
NodeID : ST_UANodeID;
nNodeHdl : DWORD;
(* Declarations for UA_Write *)
fbUA_Write : UA_Write;
stIndexRange : ARRAY [1..nMaxIndexRange] OF ST_UAIndexRange;
nIndexRangeCount : UINT;
stNodeAddInfo : ST_UANodeAdditionalInfo;
sNodeIdentifier: STRING(MAX_STRING_LENGTH) := 'MAIN.nNumber';
nWriteData: INT := 42;
(* Declarations for UA_NodeReleaseHandle *)
fbUA_NodeReleaseHandle : UA_NodeReleaseHandle;
Implementation:
CASE iState OF
0:
[...]
2: (* GetNS Index *)
fbUA_GetNamespaceIndex(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NamespaceUri := sNamespaceUri,
NamespaceIndex => nNamespaceIndex
);
IF NOT fbUA_GetNamespaceIndex.Busy THEN
fbUA_GetNamespaceIndex(Execute := FALSE);
IF NOT fbUA_GetNamespaceIndex.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_GetNamespaceIndex.ErrorID;
iState := 6;
END_IF
END_IF
3: (* UA_NodeGetHandle *)
NodeID.eIdentifierType := eUAIdentifierType_String;
NodeID.nNamespaceIndex := nNamespaceIndex;
NodeID.sIdentifier := sNodeIdentifier;
fbUA_NodeGetHandle(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeID := NodeID,
NodeHdl => nNodeHdl);
IF NOT fbUA_NodeGetHandle.Busy THEN
fbUA_NodeGetHandle(Execute := FALSE);
IF NOT fbUA_NodeGetHandle.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_NodeGetHandle.ErrorID;
iState := 6;
END_IF
END_IF
4: (* UA_Write *)
fbUA_Write(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeHdl := nNodeHdl,
stNodeAddInfo := stNodeAddInfo,
cbData := SIZEOF(nWriteData),
pVariable := ADR(nWriteData));
IF NOT fbUA_Write.Busy THEN
fbUA_Write(
Execute := FALSE,
pVariable := ADR(nWriteData));
IF NOT fbUA_Write.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_Write.ErrorID;
iState := 6;
END_IF
END_IF
5: (* Release Node Handle *)
fbUA_NodeReleaseHandle(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeHdl := nNodeHdl);
IF NOT fbUA_NodeReleaseHandle.Busy THEN
fbUA_NodeReleaseHandle(Execute := FALSE);
IF NOT fbUA_NodeReleaseHandle.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_NodeReleaseHandle.ErrorID;
iState := 6;
END_IF
END_IF
6:
[...]
END_CASE
Calling methods
The following section describes how you use the function block TcX_PLCopen_OpcUa to call methods on a local or remote OPC UA server. The following function blocks are required to connect to an OPC UA server, call UA methods, and subsequently interrupt the session: UA_Connect, UA_GetNamespaceIndex, UA_MethodGetHandle, UA_MethodCall, UA_MethodReleaseHandle, UA_Disconnect.
The schematic workflow of each TwinCAT OPC UA Client can be categorized into three different phases: Preparation, Work and Cleanup.
The use case described in this section can be visualized as follows:

- The function block UA_Connect requires the following information in order to be able to establish a connection to a local or remote OPC UA server (see also How to establish a connection):
- Server URL
- Session Connect Information
- The function block UA_GetNamespaceIndex requires a Connection Handle (from UA_Connect) and a NamespaceURI for resolution to a NamespaceIndex, which is later used by UA_NodeGetHandle to capture a node handle (see also How to determine communication parameters).
- The function block UA_MethodGetHandle requires a connection handle (from UA_Connect), an ObjectNodeID and a MethodNodeID to capture a method handle (see also How to determine communication parameters).
- The function block UA_MethodCall requires a connection handle (from UA_Connect), a method handle (from UA_MethodGetHandle) and information about the input and output arguments of the method that is to be called. Information about the input arguments is represented by the input parameters pInputArgInfo and pInputArgData of UA_MethodCall. Information about the output parameters is represented by the pOutputArgInfo and pOutputArgData input parameters of UA_MethodCall. The input parameter pOutputArgInfoAndData then represents a pointer to a structure containing the results of the method call, including all output parameters. The following code snippet calculates and creates the pInputArgInfo and pInputArgData parameters in the M_Init method.
- The function block UA_NodeReleaseHandle requires a connection handle (from UA_Connect) and a method handle (from UA_MethodGetHandle).
M_Init initialization method of the function block containing the UA method call:
MEMSET(ADR(nInputData),0,SIZEOF(nInputData));
nArg := 1;
(********** Input parameter 1 **********)
InputArguments[nArg].DataType := eUAType_Int16;
InputArguments[nArg].ValueRank := -1; (* Scalar = -1 or Array *)
InputArguments[nArg].ArrayDimensions[1] := 0; (* Number of Dimension in case its an array *)
InputArguments[nArg].nLenData := SIZEOF(numberIn1); (* Length if its a STRING *)
IF nOffset + SIZEOF(numberIn1) > nInputArgSize THEN
bInputDataError := TRUE;
RETURN;
ELSE
MEMCPY(ADR(nInputData)+nOffset,ADR(numberIn1),SIZEOF(numberIn1)); (* VALUE in BYTES FORM *)
nOffset := nOffset + SIZEOF(numberIn1);
END_IF
nArg := nArg + 1;
(********** Input parameter 2 **********)
InputArguments[nArg].DataType := eUAType_Int16;
InputArguments[nArg].ValueRank := -1; (* Scalar = -1 or Array *)
InputArguments[nArg].ArrayDimensions[1] := 0; (* Number of Dimension in case its an array *)
InputArguments[nArg].nLenData := SIZEOF(numberIn2); (* Length if its a STRING *)
IF nOffset + SIZEOF(numberIn2) > nInputArgSize THEN
bInputDataError := TRUE;
RETURN;
ELSE
MEMCPY(ADR(nInputData)+nOffset,ADR(numberIn2),SIZEOF(numberIn2));(* VALUE in BYTES FORM *)
nOffset := nOffset + SIZEOF(numberIn2);
END_IF
cbWriteData := nOffset;
Declaration:
(* Declarations for UA_GetNamespaceIndex *)
fbUA_GetNamespaceIndex : UA_GetNamespaceIndex;
nNamespaceIndex : UINT;
(* Declarations for UA_MethodGetHandle *)
fbUA_MethodGetHandle: UA_MethodGetHandle;
ObjectNodeID: ST_UANodeID;
MethodNodeID: ST_UANodeID;
nMethodHdl: DWORD;
(* Declarations for UA_MethodCall *)
fbUA_MethodCall: UA_MethodCall;
sObjectNodeIdIdentifier : STRING(MAX_STRING_LENGTH) := 'MAIN.fbMathematics';
sMethodNodeIdIdentifier : STRING(MAX_STRING_LENGTH) := 'MAIN.fbMathematics#M_Mul';
nAdrWriteData: PVOID;
numberIn1: INT := 42; // change according to input value and data type
numberIn2: INT := 42; // change according to input value and data type
numberOutPro: DINT; // result (output parameter of M_Mul())
cbWriteData: UDINT; // calculated automatically by M_Init()
InputArguments: ARRAY[1..2] OF ST_UAMethodArgInfo; // change according to input parameters
stOutputArgInfo: ARRAY[1..1] OF ST_UAMethodArgInfo; // change according to output parameters
stOutputArgInfoAndData: ST_OutputArgInfoAndData;
nInputData: ARRAY[1..4] OF BYTE; // numberIn1(INT16)(2) + numberIn2(INT16)(2)
nOffset: UDINT; // calculated by M_Init()
nArg: INT; // used by M_Init()
(* Declarations for UA_MethodReleaseHandle *)
fbUA_MethodReleaseHandle: UA_MethodReleaseHandle;
Implementation:
CASE iState OF
0:
[...]
2: (* GetNS Index *)
fbUA_GetNamespaceIndex(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NamespaceUri := sNamespaceUri,
NamespaceIndex => nNamespaceIndex);
IF NOT fbUA_GetNamespaceIndex.Busy THEN
fbUA_GetNamespaceIndex(Execute := FALSE);
IF NOT fbUA_GetNamespaceIndex.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_GetNamespaceIndex.ErrorID;
iState := 7;
END_IF
END_IF
3: (* Get Method Handle *)
ObjectNodeID.eIdentifierType := eUAIdentifierType_String;
ObjectNodeID.nNamespaceIndex := nNamespaceIndex;
ObjectNodeID.sIdentifier := sObjectNodeIdIdentifier;
MethodNodeID.eIdentifierType := eUAIdentifierType_String;
MethodNodeID.nNamespaceIndex := nNamespaceIndex;
MethodNodeID.sIdentifier := sMethodNodeIdIdentifier;
M_Init();
IF bInputDataError = FALSE THEN
iState := iState + 1;
ELSE
bBusy := FALSE;
bError := TRUE;
nErrorID := 16#70A; //out of memory
END_IF
4: (* Method Get Handle *)
fbUA_MethodGetHandle(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
ObjectNodeID := ObjectNodeID,
MethodNodeID := MethodNodeID,
MethodHdl => nMethodHdl);
IF NOT fbUA_MethodGetHandle.Busy THEN
fbUA_MethodGetHandle(Execute := FALSE);
IF NOT fbUA_MethodGetHandle.Error THEN
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_MethodGetHandle.ErrorID;
iState := 6;
END_IF
END_IF
5: (* Method Call *)
stOutputArgInfo[1].nLenData := SIZEOF(stOutputArgInfoAndData.pro);
fbUA_MethodCall(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
MethodHdl := nMethodHdl,
nNumberOfInputArguments := nNumberOfInputArguments,
pInputArgInfo := ADR(InputArguments),
cbInputArgInfo := SIZEOF(InputArguments),
pInputArgData := ADR(nInputData),
cbInputArgData := cbWriteData,
pInputWriteData := 0,
cbInputWriteData := 0,
nNumberOfOutputArguments := nNumberOfOutputArguments,
pOutputArgInfo := ADR(stOutputArgInfo),
cbOutputArgInfo := SIZEOF(stOutputArgInfo),
pOutputArgInfoAndData := ADR(stOutputArgInfoAndData),
cbOutputArgInfoAndData := SIZEOF(stOutputArgInfoAndData));
IF NOT fbUA_MethodCall.Busy THEN
fbUA_MethodCall(Execute := FALSE);
IF NOT fbUA_MethodCall.Error THEN
iState := iState + 1;
numberOutPro := stOutputArgInfoAndData.pro;
ELSE
bError := TRUE;
nErrorID := fbUA_MethodCall.ErrorID;
iState := 6;
END_IF
END_IF
6: (* Release Method Handle *)
fbUA_MethodReleaseHandle(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
MethodHdl := nMethodHdl);
IF NOT fbUA_MethodReleaseHandle.Busy THEN
fbUA_MethodReleaseHandle(Execute := FALSE);
bBusy := FALSE;
IF NOT fbUA_MethodReleaseHandle.Error THEN
iState := 7;
ELSE
bError := TRUE;
nErrorID := fbUA_MethodReleaseHandle.ErrorID;
iState := 7;
END_IF
END_IF
7:
[...]
END_CASE