Beruflich Dokumente
Kultur Dokumente
Net DLLs
Contents
1.
1.1.1.
Constructor.................................................................................................................... 3
1.1.2.
Methods......................................................................................................................... 3
1.1.3.
Properties....................................................................................................................... 3
1.2.
1.2.1.
1.2.2.
C# - Constructor............................................................................................................. 5
1.2.3.
C# - Properties............................................................................................................... 6
1.2.4.
C# - Methods.................................................................................................................. 6
1.2.5.
1.3.
1.3.1.
1.3.2.
VB .NET - Constructor.................................................................................................. 10
1.3.3.
VB .NET - Properties.................................................................................................... 10
1.3.4.
VB .NET - Methods....................................................................................................... 11
1.3.5.
1.4.
1.5.
1.5.1.
1.6.
1.6.1.
1.6.2.
1.7.
1.7.1.
1.8.
Cicode Example........................................................................................................... 18
1.8.1.
1.8.2.
1.8.3.
1.8.4.
1.8.5.
1.8.6.
1.8.7.
1.8.8.
1.9.
1.10.
1.11.
1.12.
1.
Prior to SCADA Expert Vijeo Citect 2015 we could only access native, or unmanaged, DLLs via the
CiCode functions:
As of v7.50, we have added the following new CiCode functions to support managed .NET Dlls:
This guide shows how to use Visual Studio 2013 Professional to create simple .NET DLLs that can be
hosted in SCADA Expert Vijeo Citect 2015.
First, we will create simple Hello World style examples in the main .NET languages; C#, VB .NET
and C++ .NET. Then we will finish off by showing a more complex example (in C# only), which will use
CTAPI to push data from the DLL back into SCADA Expert Vijeo Citect 2015.
The full code for all examples will be contained in the appendices.
1.1.
The basic anatomy of a .NET DLL, or Class Library, is the same, regardless of the language used.
They consist of the following:
Constructor
A Constructor is essentially just an initialization routine. The routine runs automatically when an
instance of a Class is created, and its purpose is to set default values for that new instance.
With respect to SCADA Expert Vijeo Citect 2015, the Constructor is triggered when we call the
DllClassCreate Cicode function.
Methods
Methods are simply functions defined in the DLL that have been made accessible from an external
host. After instantiating a Class in SCADA Expert Vijeo Citect 2015, we can call methods via the
Cicode function DllClassCallMethod.
Properties
Properties are essentially Variables defined in the DLL that have been made accessible from an
external host. After instantiating a Class in SCADA Expert Vijeo Citect 2015, we can get and set
the values of these properties via the DllClassGetProperty and DllClassSetProperty
functions.
1.2.
This is a simple example of a C# .Net DLL. The full code for this example can be found in Appendix A
Hello World (C#) full code.
1.2.1.
The first thing that we need to do is start Visual Studio and create a new project.
Select File > New > Project to open the following dialog:
Ensure you have selected Visual C# in the left pane, and Class Library on the right.
Then be sure to fill out the Name field for your project, ours is HelloWorldCsharp
Once you have done this, press OK.
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
System.Threading.Tasks;
namespace HelloWorldCsharp
{
public class HelloWorld
{
}
}
1.2.2.
Save your code by clicking on the Save All button, or Ctrl + Shift + S.
C# - Constructor
In C# the constructor must have the same name as the Class. In this case our Constructor needs to
be called HelloWorld.
The constructor for this DLL simply sets the value of an internal variable _helloWorldString to a
default value of Hello World!.
1.2.3.
C# - Properties
In C#, properties are defined by creating a public variable, with defined Get and Set routines.
For our example, we will create a new property called Message, and we will use its Get and Set
routines to read / write to our internal variable, _helloWorldString.
The code for this is as follows:
public class HelloWorld
{
1.2.4.
C# - Methods
In this example, our Method will simply display a MessageBox, containing the text value of our
property Message.
The MessageBox functionality is not already included in our program by default, so we need to add
its library as a reference to our project.
To do this:
Right click on References in the Solution Explorer and select Add Reference
DisplayMessage.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace HelloWorldCsharp
{
public class HelloWorld //Our class definition
{
1.2.5.
The Output dialog should show that the Build was successful, and the location of the
generated DLL
Navigate to this DLL and copy it to the directory of your SCADA Expert Vijeo Citect 2015
test project.
1.3.
This is a simple example of a VB .Net DLL. The full code for this example can be found in Appendix B
Hello World (VB .NET) full code.
1.3.1.
The first thing that we need to do is start Visual Studio and create a new project.
Select File > New > Project to open the following dialog:
Ensure you have selected Visual Basic in the left pane, and Class Library on the right.
Then be sure to fill out the Name field for your project, ours is HelloWorldvbnet
Once you have done this, press OK.
Rename the class Class1 to HelloWorld. This will leave you with the following code.
1.3.2.
Save your code by clicking on the Save All button, or Ctrl + Shift + S.
VB .NET - Constructor
A constructor is defined in VB .Net through a subroutine called New. It can take arguments, however
our example does not.
Public Class HelloWorld
Private _helloWorldString As String
Public Sub New() 'Our Class Constructor
_helloWorldString = "Hello World!"
End Sub
End Class
The constructor for this DLL simply sets the value of an internal variable _helloWorldString to a
default value of Hello World!.
1.3.3.
VB .NET - Properties
In VB.NET, properties are via a Property datatype, and making them Public, ReadOnly or
WriteOnly. You can define the Get and Set routines for them manually, although it may also be
handled automatically. (Note: for a ReadOnly property you would also omit a Set routine, and for a
WriteOnly property you would also omit a Get routine)
For our example, we will create a new public read / write property called Message, and we will use its
Get and Set routines to read / write to our internal variable, _helloWorldString.
1.3.4.
VB .NET - Methods
In VB .Net, methods can be Subroutines, or Functions. The difference between the two is that a
Subroutine cannot return a value, whereas a Function can. Either type can accept arguments.
Public Sub DisplayMessage() 'Our Public Method 'DisplayMessage'
MsgBox(rwMessage)
End Sub
Public Function DisplayThisMessage(ByVal sMessage As String)
'Our Public Method takes an argument, and returns a value
MsgBox(sMessage)
Return sMessage
End Function
1.3.5.
The Output dialog should show that the Build was successful, and the location of the
generated DLL
Navigate to this DLL and copy it to the Directory of you SCADA Expert Vijeo Citect 2015
test project.
1.4.
This example will lead you through creating a C++ Managed Class Library (DLL), this example is
written in Visual Studio Professional 2013.
C++ is traditionally unmanaged, however, it is also possible to write a C++ application based on CLR
(Common Language Runtime) of the .NET framework, which is managed.
The C++ code for this example can be found in Appendix C Hello World (C++ .NET) full code.
1.5.
The first thing that we need to do is start visual studio and create a new project.
Ensure you have selected Visual C++ and its sub-item CLR in the left pane
Select Class Library on the right pane.
Then be sure to fill out the Name field for your project, ours is HelloWorldCplusplus
Once you have done this, press OK.
// HelloWorldCplusplus.h
#pragma once
using namespace System;
namespace HelloWorldCplusplus {
public ref class HelloWorld
{
// TODO: Add your methods for this class here.
};
}
1.5.1.
Save your code by clicking on the Save All button, or Ctrl + Shift + S.
In C++ a constructor is declared as a Public function, with the same name as the class.
This constructor sets the default value of a private variable.
In the Header file, add the following code to define the private variable MessageString, and
declare the public function HelloWorld:
// HelloWorldCplusplus.h
#pragma once
namespace HelloWorldCplusplus {
public ref class HelloWorld
{
private:
System::String^ MessageString; //Internal Variable
public:
// Constructor - sets default values
HelloWorld();
};
}
In the Program File, add the following code to define the behavior of the HelloWorld function.
// HelloWorldCplusplus.cpp
#include "stdafx.h"
#include "HelloWorldCplusplus.h"
// Constructor implementation
HelloWorldCplusplus::HelloWorld::HelloWorld()
{
MessageString = "Hello World!"; //Defined default Value
}
1.6.
In C++ .NET, properties are defined by creating Public Property data types in the Header file, with
defined Get and Set methods.
// HelloWorldCplusplus.h
#pragma once
using namespace System;
namespace HelloWorldCplusplus {
public ref class HelloWorld
{
private:
System::String^ MessageString; //Internal Variable
public:
// Property
property System::String^ Message
{
System::String^ get() {
return MessageString;
}
void set(System::String^ value) {
MessageString = value;
}
}
};
}
1.6.1.
In C++ .NET, methods are declared in the Header file as a public function, and defined in the Program
file.
// HelloWorldCplusplus.h
#pragma once
#using <System.Windows.Forms.dll>
using namespace System;
namespace HelloWorldCplusplus {
public ref class HelloWorld
{
public:
int DisplayMessage();
};
// Method
Add the definition for the Method, into the Program File:
// HelloWorldCplusplus.cpp
#include "stdafx.h"
#include "HelloWorldCplusplus.h"
int HelloWorldCplusplus::HelloWorld::DisplayMessage()
{
System::Windows::Forms::MessageBox::Show(MessageString);
return 1;
}
1.6.2.
The Output dialog should show that the Build was successful, and the location of the
generated DLL:
Navigate to this DLL and copy it to the Directory of you SCADA Expert Vijeo Citect 2015
test project.
1.7.
The following CiCode functions are provided to interact with .NET DLLs. Their implementation
remains the same regardless of the Programming Language used to write the DLL.
1.7.1.
Cicode Example
Because we used the same Class Names, Property Names, and Method Names, we can use the
same Cicode below to interact with any of the 3 DLLs we created, C#, VB or C++.
The only line that needs to change is the line which refers to the DLLs name:
dllHandle = DllClassCreate(PathToStr("[RUN]:MyDLL.dll"),"HelloWorld")
FUNCTION testDll()
STRING sResult;
INT iResult;
OBJECT dllHandle;
ErrSet(1); //The enable capturing of IsError()
//Instantiate Class.
//This will trigger the Constructor in our DLL, which will set the
//default values, and return a handle.
dllHandle = DllClassCreate(PathToStr("[RUN]:MyDLL.dll"),"HelloWorld")
//Check Validity of handle
INT bResult = DllClassIsValid(dllHandle)
IF (bResult) THEN //If Class is Valid, then our DLL was loaded properly
//Try to read our Property 'Message'.
//The value of this property will be the default value, "Hello World!"
sResult = DllClassGetProperty(dllHandle,"Message")
//Set the property to a different string:
iResult = DllClassSetProperty(dllHandle,"Message", "My New Test Message")
IF (iResult <> 0) THEN
ErrLog("Error (Error Code = " + IntToStr(IsError()) + ")");
END
//Call our Method to open a popup containing our new message
iResult = DllClassCallMethod(dllHandle,"DisplayMessage")
IF (iResult <> 0) THEN
ErrLog("Error (Error Code = " + IntToStr(IsError()) + ")");
END
END
ErrSet(0) //The disable capturing of IsError()
END
1.8.
So far, all the interaction with our DLL has been initiated from the SCADA Expert Vijeo Citect 2015
side.
But how can we send unsolicited data to SCADA Expert Vijeo Citect from your DLL? For instance,
your DLL may be collecting data from an external source and you want to push data into SCADA
Expert Vijeo Citect whenever a new value is received.
The only way of passing data back to the host, unsolicited, is to use the CTAPI interface, which we will
demonstrate in this advanced example.
1.8.1.
This DLL will generate random values, at a configurable time interval, for a configurable tag name,
and send unsolicited updates to the locally running Citect instance via CTAPI.
This DLL will expose the following:
Properties:
target The name of the Citect Tag you wish to update (read / write)
value The current tag value (read-only)
minValue The lower bound to the randomly generated data (read / write)
maxValue The upper bound to the randomly generated data (read / write)
interval The interval at which data is randomly generated (read / write)
Methods:
CTAPI client:
Includes code to communicate to Citect SCADA via CTAPI and push data into it.
1.8.2.
The first thing that we need to do is start Visual Studio and create a new project.
Select File > New > Project to open the following dialog:
Ensure you have selected Visual C# in the left pane, and Class Library on the right.
Then be sure to fill out the Name field for your project, ours is DLL_CtapiEvents
Once you have done this, press OK.
The following code will be generated and Class1.cs is automatically opened:
using
using
using
using
using
namespace DLL_CtapiEvents
{
public class DLL_Ctapi
{
}
}
1.8.3.
Save your code by clicking on the Save All button, or Ctrl + Shift + S.
The easiest way to add CTAPI support to a C# program is to add existing file (available here) called
CTAPI.cs, which already contains the mapping to the unmanaged CTAPI DLLs.
Add this file as a reference to your project, then add its namespace to your class1.cs file.
Right click your project, select Add, then Existing Item, then navigate to your
downloaded copy of CTAPI.cs.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Citect.Util;
namespace DLL_CtapiEvents
{
public class DLL_Ctapi
{
}
}
1.8.4.
In C# the constructor must have the same name as the Class. In this case our Constructor needs to
be called Dll_Ctapi.
We have defined private variables outside the constructor, and in the constructor we give these
variables some default values.
using System.Timers;
1.8.5.
1.8.6.
The public methods can be defined as show below, along with some internally called private functions:
//Non-default libraries:
using Citect.Util; //Our CTAPI class, defined in CTAPI.cs
using System.Timers; //For our timer task
1.8.7.
generated DLL
Navigate to this DLL and copy it to the Directory of you SCADA Expert Vijeo Citect 2015
test project.
1.8.8.
The following Cicode shows how to change the properties from their default values, start, stop and
update the interval at which the random data is generated.
Note: C# is Case Sensitive, calling methods without the exact syntax will fail.
GLOBAL OBJECT hComplexDLL;
FUNCTION MyComplexDll()
INT iResult;
hComplexDLL = DllClassCreate(PathToStr("[RUN]:DLL_CtapiEvents.dll"),"DLL_Ctapi")
INT currentInterval,currentMin,currentMax, currentValue;
STRING currentTarget;
IF DllClassIsValid(hComplexDLL) THEN
iResult = DllClassSetProperty(hComplexDLL,"interval","10000");
ErrLog("setInterval: " + IntToStr(iResult));
iResult = DllClassSetProperty(hComplexDLL,"target","MyTagOne");
ErrLog("setTarget: " + IntToStr(iResult));
iResult = DllClassSetProperty(hComplexDLL,"minValue","10");
ErrLog("setMinValue: " + IntToStr(iResult));
iResult = DllClassSetProperty(hComplexDLL,"maxValue","1100");
ErrLog("setMaxValue: " + IntToStr(iResult));
currentInterval = DllClassGetProperty(hComplexDLL,"interval");
currentTarget = DllClassGetProperty(hComplexDLL,"target");
currentMin = DllClassGetProperty(hComplexDLL,"minValue");
currentMax = DllClassGetProperty(hComplexDLL,"maxValue");
currentValue = DllClassGetProperty(hComplexDLL,"value");
//Start Generating Values
iResult = DllClassCallMethod(hComplexDLL,"startGenerating");
ErrLog("startGenerating: " + IntToStr(iResult));
END
END
FUNCTION stopComplexDll()
INT iResult;
iResult = DllClassCallMethod(hComplexDLL,"stopGenerating");
ErrLog("stopGenerating: " + IntToStr(iResult));
iResult = DllClassDispose(hComplexDLL);
ErrLog("Dispose: " + IntToStr(iResult));
END
FUNCTION updateComplexDll1()
INT iResult;
iResult = DllClassSetProperty(hComplexDLL,"interval","1000");
ErrLog("setInterval: " + IntToStr(iResult));
END
FUNCTION updateComplexDll5()
INT iResult;
iResult = DllClassSetProperty(hComplexDLL,"interval","5000");
ErrLog("setInterval: " + IntToStr(iResult));
END
1.9.
//A Simple Class library that will generate random values at a defined interval, and update a
defined tag via CTAPI.
// Author: Warwick Black 2015.
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
using System.Threading.Tasks;
//Non-default libraries:
using Citect.Util; //Our CTAPI class, defined in CTAPI.cs
using System.Timers; //For our timer task
namespace DLL_CtapiEvents
{
public class DLL_Ctapi
{
static Timer _timer; // From System.Timers
private
private
private
private
private
int _timerInterval;
string _target;
double _value;
double _minValue;
double _maxValue;
1.10.
1.11.
// HelloWorldCplusplus.h
#pragma once
#using <System.Windows.Forms.dll>
using namespace System;
namespace HelloWorldCplusplus {
public ref class HelloWorld
{
private:
System::String^ MessageString; //Internal Variable
public:
// Constructor - sets default values
HelloWorld();
// Method
int DisplayMessage();
// Property
property System::String^ Message
{
System::String^ get() {
return MessageString;
}
void set(System::String^ value) {
MessageString = value;
}
};
}
// HelloWorldCplusplus.cpp
#include "stdafx.h"
#include "HelloWorldCplusplus.h"
// Constructor implementaion
HelloWorldCplusplus::HelloWorld::HelloWorld()
{
MessageString = "Hello World!"; //Defined default Value
}
int HelloWorldCplusplus::HelloWorld::DisplayMessage()
{
System::Windows::Forms::MessageBox::Show(MessageString);
return 1;
}
1.12.
//A Simple Class library that will generate random values at a defined
interval, and update a defined tag via CTAPI.
// Author: Warwick Black 2015.
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
System.Threading.Tasks;
//Non-default libraries:
using Citect.Util; //Our CTAPI class, defined in CTAPI.cs
using System.Timers; //For our timer task
namespace DLL_CtapiEvents
{
public class DLL_Ctapi
{
static Timer _timer; // From System.Timers
private
private
private
private
private
int _timerInterval;
string _target;
double _value;
double _minValue;
double _maxValue;
}
}