unit uUAClient_OLab; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ButtonGroup, StdCtrls, ActiveX, Math, ExtCtrls, OpcLabs_BaseLibExtensions_TLB, OpcLabs_BaseLibForms_TLB, OpcLabs_BaseLib_TLB, OpcLabs_EasyOpcClassicForms_TLB, OpcLabs_EasyOpcClassicInternal_TLB, OpcLabs_EasyOpcClassic_TLB, OpcLabs_EasyOpcUAForms_TLB, OpcLabs_EasyOpcUAInternal_TLB, OpcLabs_EasyOpcUA_TLB, Accessibility_TLB, mscorlib_TLB, System_Windows_Forms_TLB; const ToRight = ' +- '; type TwUAClient_OLab = class(TForm) ButtonGroup1: TButtonGroup; Panel1: TPanel; GridPanel1: TGridPanel; Label1: TLabel; UAHost: TEdit; Label2: TLabel; UAEndpoint: TEdit; Label3: TLabel; UANodeID: TEdit; Panel2: TPanel; Label4: TLabel; ListBox2: TListBox; Panel3: TPanel; ListBox1: TListBox; Label5: TLabel; Splitter1: TSplitter; procedure ButtonGroup1ButtonClicked(sender: TObject; Index: Integer); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private Client : TEasyUAClient; ClientConfiguration: TEasyUAClientConfiguration; procedure OnMonitoredItemChanged( ASender: TObject; sender: OleVariant; const eventArgs: _EasyUAMonitoredItemChangedEventArgs); procedure OnLogEntry( ASender: TObject; sender: OleVariant; const eventArgs: _LogEntryEventArgs); procedure WriteLog(s: String); procedure ComputerBrowserDialog_ShowDialog; procedure BrowseDataNodes; procedure BrowseMethods; procedure BrowseNodes; procedure CallMethod; procedure CallMultipleMethods; procedure DiscoverServers; procedure Read; procedure ReadMultiple; procedure ReadMultipleValues; procedure ReadValue; procedure SubscribeMonitoredItem; procedure SubscribeMultipleMonitoredItems; procedure WriteMultipleValues; procedure WriteValue; procedure Configuration_LogEntry; procedure UABrowseDialog_ShowDialog; procedure UADataDialog_ShowDialog; procedure UAEndpointDialog_ShowDialog; procedure UAHostAndEndpointDialog_ShowDialog; public { Public-Deklarationen } end; var wUAClient_OLab: TwUAClient_OLab; implementation {$R *.dfm} procedure TwUAClient_OLab.FormCreate(Sender: TObject); begin Client := TEasyUAClient.Create(self); Client.OnMonitoredItemChanged := OnMonitoredItemChanged; ClientConfiguration := TEasyUAClientConfiguration.Create(self); ClientConfiguration.OnLogEntry := OnLogEntry; ClientConfiguration.Connect; end; procedure TwUAClient_OLab.FormDestroy(Sender: TObject); begin FreeAndNil(Client); ClientConfiguration.Disconnect; FreeAndNil(ClientConfiguration); end; procedure TwUAClient_OLab.ButtonGroup1ButtonClicked(sender: TObject; Index: Integer); begin case index of 0:ComputerBrowserDialog_ShowDialog; 1:BrowseDataNodes; 2:BrowseMethods; 3:BrowseNodes; 4:CallMethod; 5:CallMultipleMethods; 6:DiscoverServers; 7:Read; 8:ReadMultiple; 9:ReadMultipleValues; 10:ReadValue; 11:SubscribeMonitoredItem; 12:SubscribeMultipleMonitoredItems; 13:WriteMultipleValues; 14:WriteValue; 15:Configuration_LogEntry; 16:UABrowseDialog_ShowDialog; 17:UADataDialog_ShowDialog; 18:UAEndpointDialog_ShowDialog; 19:UAHostAndEndpointDialog_ShowDialog; end; end; procedure TwUAClient_OLab.WriteLog(s: String); begin ListBox1.Items.Add(s); ListBox1.ScrollWidth := Max(ListBox1.ScrollWidth, ListBox1.Canvas.TextWidth(s)) + 10; ListBox1.TopIndex:= -1 + ListBox1.Items.Count; ListBox2.Items.Add('-----------------------------------------------'); ListBox2.Items.Add(s); ListBox2.TopIndex:= -1 + ListBox2.Items.Count; end; procedure TwUAClient_OLab.OnMonitoredItemChanged( ASender: TObject; sender: OleVariant; const eventArgs: _EasyUAMonitoredItemChangedEventArgs); begin // Display the data // Remark: Production code would check eventArgs.Exception before accessing // eventArgs.AttributeData. WriteLog('>> MonitoredItemChanged'); WriteLog(ToRight + 'NodeDescriptor:' + eventArgs.Arguments.NodeDescriptor.ToString); WriteLog(ToRight + 'AttributeData:' + eventArgs.AttributeData.ToString); end; // Event handler for the LogEntry event. It simply prints out the event. procedure TwUAClient_OLab.OnLogEntry( ASender: TObject; sender: OleVariant; const eventArgs: _LogEntryEventArgs); var s: String; begin s := '>> LogEntry:' + eventArgs.ToString; ListBox2.Items.Add(s); ListBox2.ScrollWidth := Max(ListBox2.ScrollWidth, ListBox1.Canvas.TextWidth(s)) + 10; ListBox2.TopIndex:= -1 + ListBox2.Items.Count; end; // OPC-UA functions------------------------------------------------------------- procedure TwUAClient_OLab.ComputerBrowserDialog_ShowDialog; // This example shows how to let the user browse for computers on the network. var ComputerBrowserDialog: TComputerBrowserDialog; begin WriteLog('<< ComputerBrowserDialog.ShowDialog'); ComputerBrowserDialog := TComputerBrowserDialog.Create(self); try ComputerBrowserDialog.ShowDialog(nil); WriteLog(ToRight + ComputerBrowserDialog.SelectedName); UAHost.Text := ComputerBrowserDialog.SelectedName; finally FreeAndNil(ComputerBrowserDialog); end; end; procedure TwUAClient_OLab.BrowseDataNodes; // This example shows how to obtain all data nodes (objects and variables) // under a given node of the OPC-UA address space. For each node, it displays // its browse name and node ID. var Count: Cardinal; Element: OleVariant; NodeElement: _UANodeElement; NodeElementEnumerator: IEnumVariant; NodeElements: _UANodeElementCollection; begin WriteLog('<< Browse Data Nodes'); NodeElements := Client.BrowseDataNodes( UAEndpoint.Text, // 'http://opcua.demo-this.com:51211/UA/SampleServer', // 'nsu=http://test.org/UA/Data/;i=10791'); // 'nsu=SYM:;ns=6;s=S71500ET200MP-Station_1'); 'nsu=SYM:;ns=6;s='); // 'nsu=SYM:;ns=6;s=S71500ET200MP-Station_1.Test_PLC 1'); NodeElementEnumerator := NodeElements.GetEnumerator; while (NodeElementEnumerator.Next(1, Element, Count) = S_OK) do begin NodeElement := IUnknown(Element) as _UANodeElement; WriteLog(ToRight + 'BrowseName:' + NodeElement.BrowseName.ToString); WriteLog(ToRight + 'NodeId:' + NodeElement.NodeId.ToString); end; end; procedure TwUAClient_OLab.BrowseMethods; // This example shows how to obtain all method nodes under a given node of // the OPC-UA address space. For each node, it displays its browse name and // node ID. var Count: Cardinal; Element: OleVariant; NodeElement: _UANodeElement; NodeElementEnumerator: IEnumVariant; NodeElements: _UANodeElementCollection; begin WriteLog('<< Browse Methods'); NodeElements := Client.BrowseMethods( UAEndpoint.Text, // 'http://opcua.demo-this.com:51211/UA/SampleServer', // 'nsu=http://test.org/UA/Data/;i=10755'); 'nsu=SYM:;ns=6;s='); NodeElementEnumerator := NodeElements.GetEnumerator; while (NodeElementEnumerator.Next(1, Element, Count) = S_OK) do begin NodeElement := IUnknown(Element) as _UANodeElement; WriteLog(ToRight + NodeElement.BrowseName.ToString + ': ' + NodeElement.NodeId.ToString); end; end; procedure TwUAClient_OLab.BrowseNodes; // This example shows how to obtain nodes under a given node of the OPC-UA // address space. For each node, it displays its browse name and node ID. var BrowseParameters: _UABrowseParameters; BrowsePathParser: _UABrowsePathParser; Count: Cardinal; Element: OleVariant; EndpointDescriptor: _UAEndpointDescriptor; NodeDescriptor: _UANodeDescriptor; NodeElement: _UANodeElement; NodeElementEnumerator: IEnumVariant; NodeElements: _UANodeElementCollection; begin WriteLog('<< Browse Nodes'); EndpointDescriptor := CoUAEndpointDescriptor.Create; EndpointDescriptor.UrlString := UAEndpoint.Text; NodeDescriptor := CoUANodeDescriptor.Create; BrowsePathParser := CoUABrowsePathParser.Create; BrowsePathParser.DefaultNamespaceUriString := 'nsu=SYM:;ns=6;s=S71500ET200MP-Station_1.Test_PLC 1'; //BrowsePathParser.DefaultNamespaceUriString := 'http://test.org/UA/Data/'; NodeDescriptor.BrowsePath := BrowsePathParser.Parse('[ObjectsFolder]/SYM&:'); //NodeDescriptor.BrowsePath := BrowsePathParser.Parse('[ObjectsFolder]/Data/Static/UserScalar'); BrowseParameters := CoUABrowseParameters.Create; NodeElements := Client.BrowseNodes( EndpointDescriptor, NodeDescriptor, BrowseParameters); NodeElementEnumerator := NodeElements.GetEnumerator; while (NodeElementEnumerator.Next(1, Element, Count) = S_OK) do begin NodeElement := IUnknown(Element) as _UANodeElement; WriteLog(ToRight + NodeElement.BrowseName.ToString + ': ' + NodeElement.NodeId.ToString); end; end; procedure TwUAClient_OLab.CallMethod; // This example shows how to call a single method, and pass arguments to and // from it. var I: Cardinal; Inputs: OleVariant; Outputs: OleVariant; TypeCodes: OleVariant; begin WriteLog('<< Call Method'); Inputs := VarArrayCreate([0, 10], varVariant); Inputs[0] := False; Inputs[1] := 1; Inputs[2] := 2; Inputs[3] := 3; Inputs[4] := 4; Inputs[5] := 5; Inputs[6] := 6; Inputs[7] := 7; Inputs[8] := 8; Inputs[9] := 9; Inputs[10] := 10; TypeCodes := VarArrayCreate([0, 10], varVariant); TypeCodes[0] := TypeCode_Boolean; TypeCodes[1] := TypeCode_SByte; TypeCodes[2] := TypeCode_Byte; TypeCodes[3] := TypeCode_Int16; TypeCodes[4] := TypeCode_UInt16; TypeCodes[5] := TypeCode_Int32; TypeCodes[6] := TypeCode_UInt32; TypeCodes[7] := TypeCode_Int64; TypeCodes[8] := TypeCode_UInt64; TypeCodes[9] := TypeCode_Single; TypeCodes[10] := TypeCode_Double; // Perform the operation TVarData(Outputs).VType := varArray or varVariant; TVarData(Outputs).VArray := PVarArray(Client.CallMethod( UAEndpoint.Text, UANodeID.Text, 'nsu=SYM:;ns=6;s=S71500ET200MP-Station_1.Test_PLC 1.CD01_DC01_BB170.GP.G1003_Vari', PSafeArray(TVarData(Inputs).VArray), PSafeArray(TVarData(TypeCodes).VArray))); // Display results for I := VarArrayLowBound(Outputs, 1) to VarArrayHighBound(Outputs, 1) do WriteLog(ToRight + 'outputs(' + IntToStr(I) + '): ' + Outputs[I]); end; procedure TwUAClient_OLab.CallMultipleMethods; // This example shows how to call multiple methods, and pass arguments to and // from them. var Arguments: OleVariant; CallArguments1, CallArguments2: _UACallArguments; I, J: Cardinal; Inputs1, Inputs2: OleVariant; Outputs: OleVariant; Result: _ValueArrayResult; Results: OleVariant; TypeCodes1, TypeCodes2: OleVariant; begin WriteLog('<< Call Multiple Methods'); Inputs1 := VarArrayCreate([0, 10], varVariant); Inputs1[0] := False; Inputs1[1] := 1; Inputs1[2] := 2; Inputs1[3] := 3; Inputs1[4] := 4; Inputs1[5] := 5; Inputs1[6] := 6; Inputs1[7] := 7; Inputs1[8] := 8; Inputs1[9] := 9; Inputs1[10] := 10; TypeCodes1 := VarArrayCreate([0, 10], varVariant); TypeCodes1[0] := TypeCode_Boolean; TypeCodes1[1] := TypeCode_SByte; TypeCodes1[2] := TypeCode_Byte; TypeCodes1[3] := TypeCode_Int16; TypeCodes1[4] := TypeCode_UInt16; TypeCodes1[5] := TypeCode_Int32; TypeCodes1[6] := TypeCode_UInt32; TypeCodes1[7] := TypeCode_Int64; TypeCodes1[8] := TypeCode_UInt64; TypeCodes1[9] := TypeCode_Single; TypeCodes1[10] := TypeCode_Double; CallArguments1 := CoUACallArguments.Create; CallArguments1.EndpointDescriptor.UrlString := UAEndpoint.Text; CallArguments1.NodeDescriptor.NodeId.ExpandedText := UANodeID.Text; CallArguments1.MethodNodeDescriptor.NodeId.ExpandedText := 'nsu=SYM:;ns=6;s=S71500ET200MP-Station_1.Test_PLC 1.CD01_DC01_BB170.GP.G1003_Vari'; CallArguments1.InputArguments := PSafeArray(TVarData(Inputs1).VArray); CallArguments1.InputTypeCodes := PSafeArray(TVarData(TypeCodes1).VArray); Inputs2 := VarArrayCreate([0, 11], varVariant); Inputs2[0] := False; Inputs2[1] := 1; Inputs2[2] := 2; Inputs2[3] := 3; Inputs2[4] := 4; Inputs2[5] := 5; Inputs2[6] := 6; Inputs2[7] := 7; Inputs2[8] := 8; Inputs2[9] := 9; Inputs2[10] := 10; Inputs2[11] := 'eleven'; TypeCodes2 := VarArrayCreate([0, 11], varVariant); TypeCodes2[0] := TypeCode_Boolean; TypeCodes2[1] := TypeCode_SByte; TypeCodes2[2] := TypeCode_Byte; TypeCodes2[3] := TypeCode_Int16; TypeCodes2[4] := TypeCode_UInt16; TypeCodes2[5] := TypeCode_Int32; TypeCodes2[6] := TypeCode_UInt32; TypeCodes2[7] := TypeCode_Int64; TypeCodes2[8] := TypeCode_UInt64; TypeCodes2[9] := TypeCode_Single; TypeCodes2[10] := TypeCode_Double; TypeCodes2[11] := TypeCode_String; CallArguments2 := CoUACallArguments.Create; CallArguments2.EndpointDescriptor.UrlString := UAEndpoint.Text; CallArguments2.NodeDescriptor.NodeId.ExpandedText := UANodeID.Text; CallArguments2.MethodNodeDescriptor.NodeId.ExpandedText := 'nsu=SYM:;ns=6;s=S71500ET200MP-Station_1.Test_PLC 1.CD01_DC01_BB170.GP.G1003_Vari'; CallArguments2.InputArguments := PSafeArray(TVarData(Inputs2).VArray); CallArguments2.InputTypeCodes := PSafeArray(TVarData(TypeCodes2).VArray); Arguments := VarArrayCreate([0, 1], varVariant); Arguments[0] := CallArguments1; Arguments[1] := CallArguments2; // Perform the operation TVarData(Results).VType := varArray or varVariant; TVarData(Results).VArray := PVarArray(Client.CallMultipleMethods( PSafeArray(TVarData(Arguments).VArray))); // Display results for I := VarArrayLowBound(Results, 1) to VarArrayHighBound(Results, 1) do begin WriteLog(ToRight + 'results(' + IntToStr(I) + '):'); Result := IInterface(Results[I]) as _ValueArrayResult; if Result.Exception = nil then begin TVarData(Outputs).VType := varArray or varVariant; TVarData(Outputs).VArray := PVarArray(Result.ValueArray); for J := VarArrayLowBound(Outputs, 1) to VarArrayHighBound(Outputs, 1) do WriteLog(ToRight + 'outputs(' + IntToStr(J) + '): ' + Outputs[J]); end else WriteLog(ToRight + '*** Error: ' + Result.Exception.ToString); end; end; procedure TwUAClient_OLab.DiscoverServers; // This example shows how to obtain application URLs of all OPC Unified // Architecture servers on the specified host. var Count: Cardinal; Element: OleVariant; ApplicationElement: _UAApplicationElement; ApplicationElementEnumerator: IEnumVariant; ApplicationElements: _UAApplicationElementCollection; begin WriteLog('<< Discover Servers'); // Obtain collection of server elements ApplicationElements := Client.DiscoverServers(UAHost.Text); // Display results ApplicationElementEnumerator := ApplicationElements.GetEnumerator; while (ApplicationElementEnumerator.Next(1, Element, Count) = S_OK) do begin ApplicationElement := IUnknown(Element) as _UAApplicationElement; WriteLog(ToRight + 'ApplicationElements'); WriteLog(' +-DiscoveryUriString:"' + ApplicationElement.DiscoveryUriString + '"'); WriteLog(' +-ApplicationUriString:"' + ApplicationElement.ApplicationUriString + '"'); end; end; procedure TwUAClient_OLab.Read; // This example shows how to read and display data of an attribute (value, // timestamps, and status code). var AttributeData: _UAAttributeData; begin WriteLog('<< Read attribute'); // Obtain attribute data. By default, the Value attribute of a node will be // read. AttributeData := Client.Read( UAEndpoint.Text, UANodeID.Text); // Display results WriteLog(ToRight + 'Value: ' + AttributeData.ToString); WriteLog(ToRight + 'ServerTimestamp: ' + DateTimeToStr(AttributeData.ServerTimestamp)); WriteLog(ToRight + 'SourceTimestamp: ' + DateTimeToStr(AttributeData.SourceTimestamp)); WriteLog(ToRight + 'StatusCode: ' + AttributeData.StatusCode.ToString); WriteLog(ToRight + 'AttributeData: ' + AttributeData.DisplayValue); end; procedure TwUAClient_OLab.ReadMultiple; // This example shows how to read the attributes of 4 OPC-UA nodes at once, and // display the results. var Arguments: OleVariant; I: Cardinal; ReadArguments1 : _UAReadArguments; Result: _UAAttributeDataResult; Results: OleVariant; begin WriteLog('<< Read Multiple attributes of OPC-UA nodes'); ReadArguments1 := CoUAReadArguments.Create; ReadArguments1.EndpointDescriptor.UrlString := UAEndpoint.Text; ReadArguments1.NodeDescriptor.NodeId.ExpandedText := UANodeID.Text; //ReadArguments2 := CoUAReadArguments.Create; ........... Arguments := VarArrayCreate([0, 0], varVariant); //Arguments := VarArrayCreate([0, 3], varVariant); Arguments[0] := ReadArguments1; // Perform the operation TVarData(Results).VType := varArray or varVariant; TVarData(Results).VArray := PVarArray(Client.ReadMultiple( PSafeArray(TVarData(Arguments).VArray))); // Display results for I := VarArrayLowBound(Results, 1) to VarArrayHighBound(Results, 1) do begin Result := IInterface(Results[I]) as _UAAttributeDataResult; WriteLog(ToRight + 'results(' + IntToStr(I) + ').AttributeData: ' + Result.AttributeData.ToString); end; end; procedure TwUAClient_OLab.ReadMultipleValues; // This example shows how to read the Value attributes of 3 different nodes at // once. Using the same method, it is also possible to read multiple attributes // of the same node. var ReadArguments1: _UAReadArguments; Arguments, Results: OleVariant; I: Cardinal; Result: _ValueResult; begin WriteLog('<< Read Multiple Values'); ReadArguments1 := CoUAReadArguments.Create; ReadArguments1.EndpointDescriptor.UrlString := UAEndpoint.Text; ReadArguments1.NodeDescriptor.NodeId.ExpandedText := UANodeID.Text; //ReadArguments2 := CoUAReadArguments.Create; ........ Arguments := VarArrayCreate([0, 0], varVariant); //Arguments := VarArrayCreate([0, 2], varVariant); Arguments[0] := ReadArguments1; // Obtain values. By default, the Value attributes of the nodes will be read. TVarData(Results).VType := varArray or varVariant; TVarData(Results).VArray := PVarArray(Client.ReadMultipleValues( PSafeArray(TVarData(Arguments).VArray))); // Display results for I := VarArrayLowBound(Results, 1) to VarArrayHighBound(Results, 1) do begin Result := IInterface(Results[I]) as _ValueResult; WriteLog(ToRight + 'Value: ' + String(Result.Value)); end; end; procedure TwUAClient_OLab.ReadValue; // This example shows how to read value of a single node, and display it. var Value: OleVariant; begin WriteLog('<< Read Value of single node'); Value := Client.ReadValue( UAEndpoint.Text, UANodeID.Text); WriteLog(ToRight + 'value: ' + String(Value)); end; procedure TwUAClient_OLab.SubscribeMonitoredItem; // This example shows how to subscribe to changes of a single monitored item // and display each change. begin WriteLog('<< Subscribe Monitored Item'); WriteLog(ToRight + 'Subscribing...'); Client.SubscribeMonitoredItem( UAEndpoint.Text, UANodeID.Text, 500); WriteLog (ToRight + 'Processing monitored item changed events for 500ms...'); end; procedure TwUAClient_OLab.SubscribeMultipleMonitoredItems; // This example shows how to subscribe to changes of a single monitored item // and display each change. var Arguments: OleVariant; Handle: Cardinal; HandleArray: OleVariant; I: Cardinal; MonitoredItemArguments1: _EasyUAMonitoredItemArguments; MonitoringParameters: _UAMonitoringParameters; begin WriteLog('<< Subscribe Multiple Monitored Items'); WriteLog(ToRight + 'Subscribing...'); MonitoringParameters := CoUAMonitoringParameters.Create; MonitoringParameters.SamplingInterval := 1000; MonitoredItemArguments1 := CoEasyUAMonitoredItemArguments.Create; MonitoredItemArguments1.EndpointDescriptor.UrlString := UAEndpoint.Text; MonitoredItemArguments1.NodeDescriptor.NodeId.ExpandedText := UANodeID.Text; MonitoredItemArguments1.MonitoringParameters := MonitoringParameters; //MonitoredItemArguments2 := CoEasyUAMonitoredItemArguments.Create; .... Arguments := VarArrayCreate([0, 0], varVariant); //Arguments := VarArrayCreate([0, n], varVariant); n=End of array Arguments[0] := MonitoredItemArguments1; TVarData(HandleArray).VType := varArray or varVariant; TVarData(HandleArray).VArray := PVarArray( Client.SubscribeMultipleMonitoredItems(PSafeArray(TVarData(Arguments) .VArray))); for I := VarArrayLowBound(HandleArray, 1) to VarArrayHighBound(HandleArray, 1) do begin Handle := Cardinal(HandleArray[I]); WriteLog(ToRight + 'HandleArray[' + IntToStr(I) + ']: ' + IntToHex(Handle, 6)); end; WriteLog (ToRight + 'Processing monitored item changed events for 1000ms...'); // WriteLog(ToRight + 'Unsubscribing...'); // Client.UnsubscribeAllMonitoredItems; end; procedure TwUAClient_OLab.WriteMultipleValues; // This example shows how to write values into 3 nodes at once, test for // success of each write and display the exception message in case of failure. var Arguments: OleVariant; I: Cardinal; WriteResult: _UAWriteResult; WriteValueArguments1 : _UAWriteValueArguments; Results: OleVariant; s: String; begin WriteLog('<< Write Multiple Values'); WriteValueArguments1 := CoUAWriteValueArguments.Create; s := '11'; InputQuery('Write Value into a single node', UAEndpoint.Text + #13 + UANodeID.Text + #13#13, s); WriteValueArguments1.EndpointDescriptor.UrlString := UAEndpoint.Text; WriteValueArguments1.NodeDescriptor.NodeId.ExpandedText := UANodeID.Text; WriteValueArguments1.Value := s; // WriteValueArguments2 := CoUAWriteValueArguments.Create; ..... Arguments := VarArrayCreate([0, 0], varVariant); //Arguments := VarArrayCreate([0, n], varVariant); n=End of array Arguments[0] := WriteValueArguments1; // Modify values of nodes TVarData(Results).VType := varArray or varVariant; TVarData(Results).VArray := PVarArray(Client.WriteMultipleValues( PSafeArray(TVarData(Arguments).VArray))); // Display results for I := VarArrayLowBound(Results, 1) to VarArrayHighBound(Results, 1) do begin WriteResult := IInterface(Results[I]) as _UAWriteResult; if WriteResult.Succeeded then WriteLog(ToRight + 'Result ' + IntToStr(I) + ' success') else WriteLog(ToRight + 'Result ' + IntToStr(I) + ': ' + WriteResult.Exception.GetBaseException.Message); end; end; procedure TwUAClient_OLab.WriteValue; // This example shows how to write a value into a single node. var s: String; begin WriteLog('<< Write Value into a single node'); try s := '66'; InputQuery('Write Value into a single node', UAEndpoint.Text + #13 + UANodeID.Text + #13#13, s); // Perform the operation Client.WriteValue(UAEndpoint.Text, UANodeID.Text, s); WriteLog(ToRight + 'done (for result Subscribe item)'); finally FreeAndNil(Client); end; end; procedure TwUAClient_OLab.Configuration_LogEntry; // This example demonstrates the loggable entries originating in the OPC-UA // client engine and the EasyUAClient component. var Value: OleVariant; begin WriteLog('<< Configuration LogEntry'); // Do something - invoke an OPC read, to trigger some loggable entries. Value := Client.ReadValue(UAEndpoint.Text, UANodeID.Text); WriteLog(ToRight + 'Processing log entry events for 1 minute...'); end; procedure TwUAClient_OLab.UABrowseDialog_ShowDialog; // This example shows how to let the user browse for an OPC-UA node. var BrowseDialog: TUABrowseDialog; begin WriteLog('<< UA Browse Dialog.ShowDialog'); // Instantiate the dialog object BrowseDialog := TUABrowseDialog.Create(self); try // AnchorElementTypes: // UAElementType_None, UAElementType_Host, UAElementType_Endpoint, // UAElementType_Node, UAElementType_Attribute BrowseDialog.InputsOutputs.CurrentNodeDescriptor.EndpointDescriptor.Host := UAHost.Text; BrowseDialog.Mode.AnchorElementType := UAElementType_Host; case BrowseDialog.ShowDialog(nil) of DialogResult_OK: begin // Display results WriteLog(ToRight + BrowseDialog.Outputs.CurrentNodeElement. NodeElement.ToString); UANodeID.Text := BrowseDialog.Outputs.CurrentNodeElement. NodeElement.ToString; end; DialogResult_Abort: WriteLog(ToRight + 'return Abort'); DialogResult_Cancel: WriteLog(ToRight + 'return Cancel'); DialogResult_Ignore: WriteLog(ToRight + 'return Ignore'); DialogResult_No: WriteLog(ToRight + 'return No'); DialogResult_None: WriteLog(ToRight + 'return None'); DialogResult_Retry: WriteLog(ToRight + 'return Retry'); DialogResult_Yes: WriteLog(ToRight + 'return Yes'); end; finally FreeAndNil(BrowseDialog); end; end; procedure TwUAClient_OLab.UADataDialog_ShowDialog; // This example shows how to let the user browse for an OPC-UA data node // (a Data Variable or a Property). var DataDialog: TUADataDialog; begin WriteLog('<< UA Data Dialog.ShowDialog'); // Instantiate the dialog object DataDialog := TUADataDialog.Create(self); try DataDialog.EndpointDescriptor.Host := UAHost.Text; //UrlString := UAEndpoint.Text; DataDialog.UserPickEndpoint := True; case DataDialog.ShowDialog(nil) of DialogResult_OK: begin // Display results WriteLog(ToRight + 'EndpointDescriptor: ' + DataDialog.EndpointDescriptor.ToString); UAEndpoint.Text := DataDialog.EndpointDescriptor.ToString+'/'+DataDialog.NodeElement.ToString; WriteLog(ToRight + 'NodeElement: ' + DataDialog.NodeElement.ToString); end; DialogResult_Abort: WriteLog(ToRight + 'return Abort'); DialogResult_Cancel: WriteLog(ToRight + 'return Cancel'); DialogResult_Ignore: WriteLog(ToRight + 'return Ignore'); DialogResult_No: WriteLog(ToRight + 'return No'); DialogResult_None: WriteLog(ToRight + 'return None'); DialogResult_Retry: WriteLog(ToRight + 'return Retry'); DialogResult_Yes: WriteLog(ToRight + 'return Yes'); end; finally FreeAndNil(DataDialog); end; end; procedure TwUAClient_OLab.UAEndpointDialog_ShowDialog; // This example shows how to let the user browse for an OPC-UA server endpoint. var EndpointDialog: TUAEndpointDialog; begin WriteLog('<< UA Endpoint Dialog.ShowDialog'); // Instantiate the dialog object EndpointDialog := TUAEndpointDialog.Create(self); try EndpointDialog.DiscoveryHost := UAHost.Text; case EndpointDialog.ShowDialog(nil) of DialogResult_OK: begin // Display results WriteLog(ToRight + 'EndpointDescriptor: ' + EndpointDialog.ApplicationElement.ToString); UAEndpoint.Text := EndpointDialog.ApplicationElement.ToString; end; DialogResult_Abort: WriteLog(ToRight + 'return Abort'); DialogResult_Cancel: WriteLog(ToRight + 'return Cancel'); DialogResult_Ignore: WriteLog(ToRight + 'return Ignore'); DialogResult_No: WriteLog(ToRight + 'return No'); DialogResult_None: WriteLog(ToRight + 'return None'); DialogResult_Retry: WriteLog(ToRight + 'return Retry'); DialogResult_Yes: WriteLog(ToRight + 'return Yes'); end; finally FreeAndNil(EndpointDialog); end; end; procedure TwUAClient_OLab.UAHostAndEndpointDialog_ShowDialog; // This example shows how to let the user browse for a host (computer) and // an endpoint of an OPC-UA server residing on it. var HostAndEndpointDialog: TUAHostAndEndpointDialog; begin WriteLog('<< UA Host And Endpoint Dialog.ShowDialog'); // Instantiate the dialog object HostAndEndpointDialog := TUAHostAndEndpointDialog.Create(self); try HostAndEndpointDialog.EndpointDescriptor.Host := UAHost.Text; case HostAndEndpointDialog.ShowDialog(nil) of DialogResult_OK: begin // Display results if HostAndEndpointDialog.HostElement <> nil then begin WriteLog(ToRight + 'HostElement: ' + HostAndEndpointDialog.HostElement.ToString); UAHost.Text := HostAndEndpointDialog.HostElement.ToString; end; WriteLog(ToRight + 'EndpointDescriptor: ' + HostAndEndpointDialog.ApplicationElement.ToString); UAEndpoint.Text := HostAndEndpointDialog.ApplicationElement.ToString; end; DialogResult_Abort: WriteLog(ToRight + 'return Abort'); DialogResult_Cancel: WriteLog(ToRight + 'return Cancel'); DialogResult_Ignore: WriteLog(ToRight + 'return Ignore'); DialogResult_No: WriteLog(ToRight + 'return No'); DialogResult_None: WriteLog(ToRight + 'return None'); DialogResult_Retry: WriteLog(ToRight + 'return Retry'); DialogResult_Yes: WriteLog(ToRight + 'return Yes'); end; finally FreeAndNil(HostAndEndpointDialog); end; end; end.