[Imported] Accessing Automation Interface via COM object (Delphi example)
>>Message imported from previous forum - Category:Scripts and Tips<< User: mchartrand, originally posted: 2018-10-25 20:05:19 Id:296 This is a re-posting from the obsoleted (October 2018) "Schneider Electric Telemetry & SCADA" forum.
**_Dmytro: Not many people realize how simple it can be to access ClearSCADA database from an outside application using the good old COM object, supported by all the old and new programming environments. No libraries (except for the built-in ones) and no third party DLLs are required. Here is my example for Object Pascal/Delphi. It renames a group, adds a value to a point's history and displays it's current value. You will need one button and one edit component on your Delphi form._**
_uses ..., ComObj ... procedure TForm1.Button1Click(Sender: TObject); var Svr,Obj,His: Variant; begin Svr:=CreateOleObject('Serck.ScxV6Server'); Svr.Connect('Main','Engineer','Password1'); Obj:=Svr.FindObject('Patients.Unknown08'); // Find that new guy occupying bed No8. Obj.Name:='English'; // Let's call him Mr.English from now on. Obj:=Svr.FindObject('Patients.English.Temperature'); His:=Obj.Interface.Historic; // I took his temperature at this time yesterday, while His.LoadDataValue(0, 192, Now-1, 36.6); // the system was down. Edit1.Text:=Obj.Interface.CurrentValueFormatted; // By the way, what is it now? Svr.Disconnect; end;_
**_Notes: 1. Versions: ClearSCADA 2015 R2 (Build 77.5882); Windows 7 Pro SP1 64-bit; Delphi 7.0 . 2. ComObj is a standard Object Pascal unit (supplied with all versions). 3. What is "Serck"? It is the company that originated ClearSCADA very-very long time ago. This Windows class group serves better than a monument in the middle of Newcaste, doesn't it? 🙂 4. The "Now" function returns local PC time. The "LoadDataValue" procedure interprets the input time as UTC. In this regard the example is only good for a UTC zone._**
**_Dmytro: Related Mysteries An extract from the "Server Automation" online help: (See ss1.jpg) 1. "Historic" is neither a method nor a property, it is an aggregate. However, and fortunately, for some reason it works through the Interface method. "Fortunately" because of the following. 2. The standard way of accessing an aggregate, as prescribed by the help, is by calling the Aggregate method on the object. However the call His:=Obj.Aggregate('Historic'); results in error: (See ss2.jpg) 3. Maybe the Aggregate method is available through the Interface method? No, it is not, either: His:=Obj.Interface.Aggregate('Historic'); (See ss3.jpg) 4. I tried to find the Aggregate method on Database Schema. Went up and down the object tree. Is it not there; why? (Or am I blind?) Any comments from the Support or Developers on these will be appreciated._**
bevanweiss: The Aggregate should be an actual object, so it's not really a method (it doesn't take arguments).
It should just be Obj.Aggregate("Historic"), and it's of type ScxV6DbClient.ScxV6Aggregate
I'm a bit rusty on Pascal, if it considers array notation to use the  syntax, then it would be:
His := Obj.Aggregate['Historic']
AWoodland: Aggregate isn't a property or method in the database, hence why you can't find it in the schema and can't use it in logic for example, it is just provided by the DLL to access the aggregates.
I'll have a play and see what I use, whilst the COM automation interface is good for backwards compatability (and easier to just hack stuff together) the .NET API should be the preferred choice for anything serious.
What is "Serck"? It is the company that originated ClearSCADA very-very long time ago. This Windows class group serves better than a monument in the middle of Newcaste, doesn't it? 🙂
FWIW, the middle of Coventry, UK would be better than Newcastle, Australia as ClearSCADA was never developed at Serck Controls Australia (small bits were) 🙂
That is one of the good things about using the COM object, I still get to use 'Serck' occasionally. Same reason I still have the Serck swoosh on the window on the side of my car (that and the fact the glue is so solid I can't get the **bleep** thing off)...
**_Dmytro: Exactly. That's why it looks to me as "not working for right reasons and working for wrong reasons". As per the help, the Interface method provides access to properties and methods of an object. How come it provides access to such "a funny thing" (as it appears in the "His:=Obj.Interface.Historic" assignment) as Historic. It looks more like a method access here, hence my further exploring per notes 3 and 4. And, again, as per the help (see ss1.jpg), anything accessible via the Interface method I should be able to find in the schema tree (and not as a literal reference which the name of the aggregate is)._**
AWoodland: Probably to provide consistency in data access, fwiw you can do similar in logic and also for accessing specific alarm conditions.
**_Dmytro: You are right, and this was my understanding too. However, as noted in note 2, it doesn't work (anymore?) via COM. The message ss2.jpg simply spells out the response received from ClearSCADA AI, and has nothing to do with Delphi syntax. By the way, ScxV6DbClient.ScxV6Aggregate is a VB type. Bypassing it is done by calling Windows class Serck.ScxV6Server._**
bevanweiss: I think you've misquoted me 😉 I did say exactly that it is of type 'ScxV6DbClient.ScxV6Aggregate'. It's not really a 'VB type', it's just a COM Class Definition (COM type), not bound to VB, especially since it's not written in VB but C/C++ instead. For the Historic aggregate, it's actually a subtype of this, which is CHistoryBase (or CDNP3History.. depends on the associated DB object type).
It certainly still works elsewhere, none of the AI code that we use has broken in ClearSCADA 2015R2. I believe this will be a Delphi oddity. Are you able to access any Aggregates?
From the Server Automation help (ClearSCADA 2015R2)
Example The following example written in VB.NET shows how to use the Aggregate method to retrieve the optional historic storage area of a point:
_Dim Svr as ScxV6Server Dim Obj as ScxV6Object Dim His as ScxV6Aggregate ' Connect to the server Svr = new ScxV6Server Svr.Connect "MAIN", "", "" ' Find the point in the database Set Obj = Svr.FindObject("Group.Point") ' Use GetAggregate to get the optional historic storage Set His = Obj.Aggregate("Historic") If His is Nothing Then MsgBox "Historic not defined" Else ' Access properties and method of the His object End If_
I'd check that your Delphi logic matches this. And that you actually have a Historic aggregate associated with the object that you're trying to use this code with. If you haven't enabled the Historic tickbox on the DB object then the aggregate reference will be Nothing ("Historic not defined")
**_Dmytro: Adam: And it is good it does, as the standard format doesn't work. Took me awhile to figure out this workaround 🙂 Bevan: The above code works fine. This topic is a working example of using COM object to access CS AI. And the small print in the first post is really all the code that is required (that's the beauty of it). It is just the odd behaviour that I observed that made me post the "Mysteries" part. The BV.NET example uses predefined types (they are probably as well not defined in VB-specific libraries, but rather in a C++-written DLL, as you clarified to me regarding the ScxV6DbClient.ScxV6Aggregate). The above Pascal example is not using any predefined types: all I needed is a few Variants. Delphi employs late binding (by the means of interface IDispatch, defined in the core unit "system.pas"). This allows me to not care what language the type library is written in, and if it exists at all ;)_**
bevanweiss: IDispatch is the COM late-binding mechanism. It's not Delphi specific.
Statically typing your variables as much as possible is the recommended course of action. It's not always possible, but you should strive to do this.
When using VB/C# it's also possible to just type everything as 'var', but it's really not helpful to a programmer coming after you (including yourself 'post-memory' of what your code was doing).
That the obj.Aggregate("Historic") method call did not work has me a bit surprised. It would be good if you could try this with a few of the other possible aggregates also, to confirm that it is such a Delphi issue. Maybe like the UserMethods aggregate, which exists on every object.
Or perhaps it's Delphi not liking the Aggregate method call without knowing explicitly that the object has such a method available. You might need to statically type the object reference as being to an ScxV6DbClient.ScxV6Object (which from the type library Delphi would know has an Aggregate method).