Sie sind auf Seite 1von 39

Creating Custom .

Net DLLs

Contents
1.

Creating Custom .NET DLLs.......................................................................................................... 3


1.1.

Anatomy of a .NET DLL or Class Library..............................................................................3

1.1.1.

Constructor.................................................................................................................... 3

1.1.2.

Methods......................................................................................................................... 3

1.1.3.

Properties....................................................................................................................... 3

1.2.

C# - Hello World DLL........................................................................................................... 4

1.2.1.

C# - Creating a new class library...................................................................................4

1.2.2.

C# - Constructor............................................................................................................. 5

1.2.3.

C# - Properties............................................................................................................... 6

1.2.4.

C# - Methods.................................................................................................................. 6

1.2.5.

C# - Building the DLL..................................................................................................... 7

1.3.

VB .NET - Hello World DLL.................................................................................................. 9

1.3.1.

VB .NET - Creating a new class library..........................................................................9

1.3.2.

VB .NET - Constructor.................................................................................................. 10

1.3.3.

VB .NET - Properties.................................................................................................... 10

1.3.4.

VB .NET - Methods....................................................................................................... 11

1.3.5.

VB .NET - Building the DLL.......................................................................................... 11

1.4.

C++ .Net - Hello World......................................................................................................... 13

1.5.

C++ .NET - Creating a new class library..............................................................................13

1.5.1.
1.6.

C++ .NET - Constructor................................................................................................14

C++ .NET - Properties.......................................................................................................... 15

1.6.1.

C++ .NET - Methods.................................................................................................... 16

1.6.2.

C++ .NET Building the DLL.......................................................................................17

1.7.

Interfacing with .NET DLLs using Cicode.............................................................................18

1.7.1.
1.8.

Cicode Example........................................................................................................... 18

Advanced C# example Completing the loop via CTAPI....................................................19

1.8.1.

Advanced C# example Overview:.............................................................................19

1.8.2.

Advanced C# example Creating a new class library.................................................20

1.8.3.

Advanced C# example Add Reference to CTAPI libraries.........................................21

1.8.4.

Advanced C# example Constructor...........................................................................22

1.8.5.

Advanced C# example Properties.............................................................................23

1.8.6.

Advanced C# example Methods...............................................................................24

1.8.7.

Advanced C# example Building the DLL...................................................................24

1.8.8.

Advanced C# example Cicode..................................................................................26

1.9.

Appendix A Hello World (C#) full code..........................................................................27

1.10.

Appendix B Hello World (VB .NET) full code................................................................30

1.11.

Appendix C Hello World (C++ .NET) full code..............................................................31

1.12.

Appendix D Advanced C# Example Full code................................................................32

1.

Creating Custom .NET DLLs

Prior to SCADA Expert Vijeo Citect 2015 we could only access native, or unmanaged, DLLs via the
CiCode functions:

DllOpen, DllCall, DllCallEx, DllClose

As of v7.50, we have added the following new CiCode functions to support managed .NET Dlls:

DllClassCreate, DllClassIsValid, DllClassCallMethod,


DllClassSetProperty, DllClassGetProperty, DllClassDispose

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.

Anatomy of a .NET DLL or Class Library

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.

C# - Hello World DLL

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.

C# - Creating a new class library

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.

The following code will be generated and Class.cs is automatically opened:

Change the line public class Class1 to public class HelloWorld


Your code will now look like this:

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!.

public class HelloWorld


{
private string _helloWorldString; //Internal variable
public HelloWorld() //Our Constructor
{
_helloWorldString = "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
{

public string Message //Our Property Message


{
get //Called By Cicode: DLLClassGetProperty(){
return _helloWorldString;
}
set //Called By Cicode: DLLClassSetProperty(){
_helloWorldString = value;
}
}

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

In the resulting popup, scroll down until you find System.Windows.Forms


Select the checkbox to the left of it
Press OK.

Now we have added a reference to System.Windows.Forms to our project


We still need to reference the new namespace in our code using the line
o using System.Windows.Forms
We can now reference the MessageBox.Show() function in the definition of our Method

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
{

public void DisplayMessage()


//Method DisplayMessage, called by Cicode: DLLClassCallMethod()
{
MessageBox.Show(Message);
}
}
}

1.2.5.

C# - Building the DLL

Ensure you have selected the Release build profile:

Select Build > Build Solution

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.

VB .NET - Hello World DLL

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.

VB .NET - Creating a new class library

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.

The following code will be generated and Class1.vb is automatically opened:

Rename the class Class1 to HelloWorld. This will leave you with the following code.

Public Class HelloWorld


End Class

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.

Public Property Message As String 'Our Public read/write property 'rwMessage'


Get
Return CStr(_helloWorldString)
End Get
Set(value As String)
_helloWorldString = value
End Set
End Property

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.

VB .NET - Building the DLL

Ensure you have selected the Release build profile:

Select Build > Build Solution

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.

C++ .Net - Hello World

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.

C++ .NET - Creating a new class library

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++ 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.

The following code will be generated and HelloWorldCplusplus.h is automatically


opened:

All our changes will be in either HelloWorldCplusplus.h (Header file) or

HelloWorldCplusplus.cpp (Program File).


The Header file is for declarations, and the Program file is for the Program code.
Rename the class Class1 to HelloWorld. This will leave you with the following code:

// 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.

C++ .NET - Constructor

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.

C++ .NET - Properties

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.

C++ .NET - Methods

In C++ .NET, methods are declared in the Header file as a public function, and defined in the Program
file.

In the header file, add the function declaration:

// 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.

C++ .NET Building the DLL

Ensure you have selected the Release build profile:

Select Build > Build Solution

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.

Interfacing with .NET DLLs using Cicode

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.

DllClassCreate, DllClassIsValid, DllClassCallMethod,


DllClassSetProperty, DllClassGetProperty, DllClassDispose

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.

Advanced C# example Completing the loop via CTAPI

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.

Advanced C# example Overview:

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:

StartGenerating() Starts generating data, and pushes results via CTAPI

StopGenerating() Stops generating data, stop notifying Citect.

CTAPI client:

Includes code to communicate to Citect SCADA via CTAPI and push data into it.

1.8.2.

Advanced C# example Creating a new class library

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:

Change the line public class Class1 to public class DLL_Ctapi


using
using
using
using
using

Your code will now look like this:


System;
System.Collections.Generic;
System.Linq;
System.Text;
System.Threading.Tasks;

namespace DLL_CtapiEvents
{
public class DLL_Ctapi
{
}
}

1.8.3.

Save your code by clicking on the Save All button, or Ctrl + Shift + S.

Advanced C# example Add Reference to CTAPI libraries

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.

Add the namespace Citect.Util to your class1.cs file.

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.

Advanced C# example Constructor

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;

public class DLL_Ctapi


{

static Timer _timer; // From System.Timers


private int _timerInterval;
private string _target;
private double _value;
private double _minValue;
private double _maxValue;
public DLL_Ctapi() //Class Constructor, called by Cicode: DLLClassCreate()
{
_timerInterval = 3000; //Set default interval to 30 seconds.
_target = "Tag1"; //Set default name to 'Tag1'
_minValue = 0;
_maxValue = 100;
}
}

1.8.5.

Advanced C# example Properties

We expose the requisite properties with the below code:

//READ/WRITE, Tag name of the Targeted Tag


public string target
{
get //Called By Cicode: DLLClassGetProperty()
{
return _target;
}
set //Called By Cicode: DLLClassSetProperty()
{
_target = value;
}
}
//READ ONLY, This is the current value
public double value
{
get //Called By Cicode: DLLClassGetProperty()
{
return _value;
}
}
//READ/WRITE, This is the lowest generated value
public double minValue
{
get //Called By Cicode: DLLClassGetProperty()
{
return _minValue;
}
set //Called By Cicode: DLLClassSetProperty()
{
_minValue = value;
}
}
//READ/WRITE, This is the highest generated value
public double maxValue
{
get //Called By Cicode: DLLClassGetProperty()
{
return _maxValue;
}

//READ/WRITE, Tag name of the Targeted Tag


public string target
{
get //Called By Cicode: DLLClassGetProperty()
{
return _target;
}
set //Called By Cicode: DLLClassSetProperty()
{
_target = value;
}
}
//READ ONLY, This is the current value
public double value
{
get //Called By Cicode: DLLClassGetProperty()
{
return _value;
}
}
//READ/WRITE, This is the lowest generated value
public double minValue
{
get //Called By Cicode: DLLClassGetProperty()
{
return _minValue;
}
set //Called By Cicode: DLLClassSetProperty()
{
_minValue = value;
}
}
//READ/WRITE, This is the highest generated value
public double maxValue
{
get //Called By Cicode: DLLClassGetProperty()
{
return _maxValue;
}
set //Called By Cicode: DLLClassSetProperty()
{
_maxValue = value;
}
}
//READ/WRITE, The interval that our random data is updated at.
public int interval
{
get //Called By Cicode: DLLClassGetProperty()
{
return _timerInterval;
}
set //Called By Cicode: DLLClassSetProperty()
{
_timerInterval = value;
_timer.Interval = _timerInterval; //set the interval
}
}

1.8.6.

Advanced C# example Methods

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

public int startGenerating()


{
_timer = new Timer(interval); //sets up new timer, at our interval rate.
_timer.AutoReset = true; //So it triggers everytime, not just once.
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed)//Event handler
_timer.Enabled = true; // Enable Timer
return 0;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
Random random = new Random();
_value = Math.Round(random.NextDouble() * (_maxValue - _minValue) +
_minValue,2);
string sResult = sendViaCTAPI(_target, _value.ToString());
}
public int stopGenerating()
{
_timer.Enabled = false; // Disable Timer
_timer.Dispose();
return 0;
}
//Send data via CTAPI to the local running Citect Client
private string sendViaCTAPI(string tagName, string tagValue)
{
StringBuilder sResultBuffer = new StringBuilder(255);
uint hCTAPI = CTAPI.ctOpen("", "", "", CTAPI.CT_OPEN_BATCH);
CTAPI.ctTagWrite(hCTAPI, tagName, tagValue);
return sResultBuffer.ToString();
}

1.8.7.

Advanced C# example Building the DLL

Ensure you have selected the Release build profile:


Select Build > Build Solution
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.8.8.

Advanced C# example Cicode

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.

Appendix A Hello World (C#) full code

//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;

public DLL_Ctapi() //Class Constructor, called by Cicode: DLLClassCreate()


{
_timerInterval = 3000; //Set default interval to 30 seconds.
_target = "Tag1"; //Set default name to 'Tag1'
_minValue = 0;
_maxValue = 100;
}
//READ/WRITE, Tag name of the Targeted Tag
public string target
{
get //Called By Cicode: DLLClassGetProperty()
{
return _target;
}
set //Called By Cicode: DLLClassSetProperty()
{
_target = value;
}
}
//READ ONLY, This is the current value
public double value
{
get //Called By Cicode: DLLClassGetProperty()
{
return _value;
}
}

//READ/WRITE, This is the lowest generated value


public double minValue
{
get //Called By Cicode: DLLClassGetProperty()
{
return _minValue;
}
set //Called By Cicode: DLLClassSetProperty()
{
_minValue = value;
}
}
//READ/WRITE, This is the highest generated value
public double maxValue
{
get //Called By Cicode: DLLClassGetProperty()
{
return _maxValue;
}
set //Called By Cicode: DLLClassSetProperty()
{
_maxValue = value;
}
}
//READ/WRITE, The interval that our random data is updated at.
public int interval
{
get //Called By Cicode: DLLClassGetProperty()
{
return _timerInterval;
}
set //Called By Cicode: DLLClassSetProperty()
{
_timerInterval = value;
_timer.Interval = _timerInterval; //set the interval
}
}
public int startGenerating()
{
_timer = new Timer(interval); //sets up new timer, at our interval rate.
_timer.AutoReset = true; //So it triggers everytime, not just once.
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed); //Defines event handler
for when the timer elapses.
_timer.Enabled = true; // Enable Timer
return 0;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
Random random = new Random();
_value = Math.Round(random.NextDouble() * (_maxValue - _minValue) +
_minValue,2);
string sResult = sendViaCTAPI(_target, _value.ToString());
}
public int stopGenerating()
{
_timer.Enabled = false; // Disable Timer
_timer.Dispose();
return 0;
}

//Send data via CTAPI to the local running Citect Client


private string sendViaCTAPI(string tagName, string tagValue)
{
StringBuilder sResultBuffer = new StringBuilder(255);
uint hCTAPI = CTAPI.ctOpen("", "", "", CTAPI.CT_OPEN_BATCH);
CTAPI.ctTagWrite(hCTAPI, tagName, tagValue);
return sResultBuffer.ToString();
}
}
}

1.10.

Appendix B Hello World (VB .NET) full code

Public Class HelloWorld


Private _helloWorldString As String
Public Sub New() 'Class Constructor
_helloWorldString = "Hello World!"
End Sub
Public Property rwMessage As String 'A Public read/write property 'rwMessage'
Get
Return CStr(_helloWorldString)
End Get
Set(value As String)
_helloWorldString = value
End Set
End Property
ReadOnly Property rMessage As String 'A readonly property 'rMessage'
Get
Return CStr(_helloWorldString)
End Get
End Property
WriteOnly Property wMessage As String 'A writeonly property 'wMessage'
Set(value As String)
_helloWorldString = value
End Set
End Property
Public Sub DisplayMessage() 'A Public Method (Subroutine) 'DisplayMessage' that cannot
return a value
MsgBox(rwMessage)
End Sub
'Our Public Method (Function) 'DisplayThisMessage' which takes an argument, and returns a
value
Public Function DisplayThisMessage(ByVal sMessage As String)
MsgBox(sMessage)
Return sMessage
End Function
End Class

1.11.

Appendix C Hello World (C++ .NET) full code

// 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.

Appendix D Advanced C# Example Full code

//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;

public DLL_Ctapi() //Class Constructor, called by Cicode:


DLLClassCreate()
{
_timerInterval = 3000; //Set default interval to 30 seconds.
_target = "Tag1"; //Set default name to 'Tag1'
_minValue = 0;
_maxValue = 100;
}
//READ/WRITE, Tag name of the Targeted Tag
public string target
{
get //Called By Cicode: DLLClassGetProperty()
{
return _target;
}
set //Called By Cicode: DLLClassSetProperty()
{
_target = value;
}
}
//READ ONLY, This is the current value
public double value
{
get //Called By Cicode: DLLClassGetProperty()
{
return _value;
}
}

//READ/WRITE, This is the lowest generated value


public double minValue
{
get //Called By Cicode: DLLClassGetProperty()
{
return _minValue;
}
set //Called By Cicode: DLLClassSetProperty()
{
_minValue = value;
}
}
//READ/WRITE, This is the highest generated value
public double maxValue
{
get //Called By Cicode: DLLClassGetProperty()
{
return _maxValue;
}
set //Called By Cicode: DLLClassSetProperty()
{
_maxValue = value;
}
}
//READ/WRITE, The interval that our random data is updated at.
public int interval
{
get //Called By Cicode: DLLClassGetProperty()
{
return _timerInterval;
}
set //Called By Cicode: DLLClassSetProperty()
{
_timerInterval = value;
_timer.Interval = _timerInterval; //set the interval
}
}
public int startGenerating()
{
_timer = new Timer(interval); //sets up new timer, at our
interval rate.
_timer.AutoReset = true; //So it triggers everytime, not
just once.
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
//Defines event handler for when the timer elapses.
_timer.Enabled = true; // Enable Timer
return 0;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
Random random = new Random();
_value = Math.Round(random.NextDouble() * (_maxValue _minValue) + _minValue,2);
}

string sResult = sendViaCTAPI(_target, _value.ToString());

public int stopGenerating()


{
_timer.Enabled = false; // Disable Timer
_timer.Dispose();
return 0;
}
//Send data via CTAPI to the local running Citect Client
private string sendViaCTAPI(string tagName, string tagValue)
{
StringBuilder sResultBuffer = new StringBuilder(255);
uint hCTAPI = CTAPI.ctOpen("", "", "", CTAPI.CT_OPEN_BATCH);

}
}

CTAPI.ctTagWrite(hCTAPI, tagName, tagValue);


return sResultBuffer.ToString();

Das könnte Ihnen auch gefallen