Skip to end of banner
Go to start of banner

CIFX-API meets C# .NET [EN]

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Allgemeines

Die CIFX-API baut auf einer nativen C/C++ Bibliothek auf. Bibliotheken für andere Entwicklungs- und/oder Laufzeit-Umgebungen gibt es nicht.
Um aus einer .NET-Applikation heraus auf solche, so genannten "nicht verwaltete" Bibliotheken bzw. Funktionen zuzugreifen, kann das so genannte P/Invoke-Framework implementiert werden.


Diese Application Note beschreibt die Herangehensweise bei der Verwendung des P/Invoke-Frameworks, im Hinblick auf die Nutzung der CIFX-API.

Dabei bezieht sich sie sich im wesentlichen auf die Umsetzungen in den Beispielen.


[DllImport("cifx32dll.dll", EntryPoint = "<native-function-name>")] 

private static extern UInt32 _myFunction( ... );


CifX-API

Handles

Wie auch bei der Verwendung der CIFX-API mit C/C++ ist die Handhabung verschiedener Handles erforderlich.

Dazu werden Pointer an die entsprechenden Funktions-Parameter übergeben.


In der .NET-Welt ist das mangels Verfügbarkeit von Pointern im klassichen Sinne nicht möglich.

Das P/Invoke-Framework stellt für diesen Zweck die Datentypen IntPtr bzw. UIntPtr zur Verfügung die innerhalb des "managed" Kontext einer .NET-Anwendung einen Pointer repräsentieren.

Ebenso wie bei einer Applikation die in C/C++ implementiert ist, müssen die Handles über die Open-Funktionen der CIFX-API geöffnet werden und während der Laufzeit der Applikation weiterexistieren (Garbage Collection).

Vor Beenden der Applikatin, sollten die Handles über die entsprechenden Close-Funktionen wieder geschlossen werden.

x68 versus x64

Die Applikation bzw. der Wrapper kann im wesentlichen ohne Veränderungen sowohl für 64-, als auch für 32-Bit Systeme übersetzt werden.

In Abhängigkeit vom Zielsystem muss hierfür die korrekte DLL des CIFX-Treibers geladen werden. Im CIFX-Treiber werden beide DLL-Versionen bereitgestellt.

Performance & PLC-Funktionen

Grundästzlich sind die PLC-Funktionen hochperformante Applikationen mit hohen Timing-Anforderungen vorgesehen. Die Verwendung von .NET an sich ist für derartige Anforderungen weniger geeignet. Bereits Windows ist standardmäßig nicht echtzeitfähig und bietet keine Möglichkeit das Zeitverhalten eines Prozesses ausreichend zu beeinflussen. Mit der .NET-Runtime kommt eine weitere Software-Schicht hinzu, die das Timing-Verhalten noch weniger voraussehbar macht.

Für Applikationen in diesem Kontext ist die Verwendung von .NET im Allgemeinen nicht zu empfehlen. Dementsprechend werden die PLC-Funktionen der CifX-API im C#-Framwork nicht unterstützt.

Hilscher - C#-Paket

Hilscher stellt ein VisualStudio-Projekt bereit, dass das P/Invoke-Frame implementiert.

Link zum Demo-Projekt:

C#.NET Demo


Innerhalb der cifXUser-Klasse werden alle CIFX-API-Funktionen im Projekt nutzbar gemacht. Außerdem stehen einige Standard-Strukturen der CIFX-API sowie Konstanten bereit.

Idealerweise kann diese Demo als Ausgangs-Projekt für die Applikations-Entwicklung genutzt werden.

Die Demo zeigt anhand eines Beispiel-Projekts auch die Einbindung der Wrapper-DLL in eine Applikation.

Hinweis

Mit .NET bzw. VisualStudio ist das Verwenden sowohl von C#.NET-, als auch von VB.NET-Projekten innerhalb einer VisualStudio-Solution möglich.

Hierfür kann einfach ein Projekt des entsprechenden Typs hinzugefügt werden: File → Add → New Project.

C# .NET - Access Violation Exception

Ein häufig auftretendes Problem bei der Verwendung von C#.NET in Verbindung mit den CIFX-Bibliotheken, ist die „Access Violation Exception“. Sie entsteht bei Verwendung eines falschen Pointer-Typen bei einer 64-Bit Applikation:

"In .NET there is an integral data type, not widely known, that is specifically designated to hold 'pointer' information: IntPtr whose size is dependent on the platform (e.g., 32-bit or 64-bit) it is running on."

Beispiel
public void SizeOfIntPtr() {Console.WriteLine( "SizeOf IntPtr is: {0}", IntPtr.Size );}


Ausgeführt auf einer 32-bit Platform bekommen sie die folgende Ausgabe:

SizeOf IntPtr is: 4

 

Auf einer 64-bit Platform sieht die Ausgabe wie folgt aus:

SizeOf IntPtr is: 8"

Lösung

Im alten Code wurden einige Funktionsparameter als 32bit Parameter gesetzt.

In der neuen Version, werden stattdessen die oben beschriebenen Pointer eingesetzt, um sowohl für 32bit als auch für 64bit Applikationen zu funktionieren.

Alt
[DllImport("cifx32dll.dll", EntryPoint = "xChannelOpen")] 

private static extern UInt32 _xChannelOpen(

UInt32 hDriver,

[MarshalAs(UnmanagedType.LPStr)] string szBoard,

UInt32 ulChannel,

[MarshalAs(UnmanagedType.U4)] ref UInt32 phChannel);
Neu
[DllImport("cifx32dll.dll",EntryPoint = "xChannelOpen")]

private static extern Int32 _xChannelOpen (

IntPtr hDriver,

[MarshalAs(UnmanagedType.LPStr)] string szBoard,

UInt32 ulChannel,

ref IntPtr phChannel);
  • No labels