Forum: PC-Programmierung Labview DLL Import


von Okocha (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen,

Programmiersprache: c++
Ziel: einen CWrapper schreiben dann in Labview importieren.

Problemstellung:
Wie soll ich der cluster für jede Funktion initialisieren?


Ich habe es einen DLL Dummy Projekt Mittel Visual studio 2012 erstellt.
Bitte seh folgende Anweisung:
http://labviewwiki.org/DLL/shared_library

Es sieht wie folgende aus:
// das baseclass Header File // zu wrappende Class
1
#ifndef _BASE_CLASS_H_
2
#define _BASE_CLASS_H_
3
4
class base
5
{
6
   public:
7
      base(double x_in);
8
      virtual ~base(void);
9
      void set_x(double x_in);
10
      void get_x(double* x_out);
11
      void sqr_x(void);
12
13
   private:
14
      double x;
15
};
16
17
#endif /* _BASE_CLASS_H_ */
// base_class cpp
1
#include "base_class.h"
2
#include <windows.h>
3
4
base::base(double x_in)
5
   {
6
      x = x_in;
7
   }
8
9
base::~base ()
10
   {
11
      /* clean up */
12
   }
13
14
void base::set_x(double x_in)
15
   {
16
      x = x_in;
17
   }
18
19
void base::get_x(double* x_out)
20
   {
21
      *x_out = x;
22
   }
23
24
void base::sqr_x(void)
25
   {
26
      x*=x;
27
   }
 c_dll_wrapper.h
1
#ifndef _C_DLL_WRAPPER_H_
2
#define _C_DLL_WRAPPER_H_
3
4
/* building a DLL */
5
#define DLLIMPORT __declspec (dllexport)
6
7
#ifdef __cplusplus
8
   extern "C" { /* using a C++ compiler */
9
#endif
10
11
   typedef struct base base; /* make the class opaque to the wrapper */
12
13
   DLLIMPORT base* create_base(double x_in);
14
   DLLIMPORT void set_x(base* LV_ref, double x_in);
15
   DLLIMPORT void get_x(base* LV_ref, double* x_out);
16
   DLLIMPORT void destroy_base(base* LV_ref);
17
   DLLIMPORT void sqr_x(base* LV_ref);
18
19
#ifdef __cplusplus
20
   }
21
#endif
22
23
24
#endif /* _C_DLL_WRAPPER_H_ */

c_dll_wrapper.cpp
1
#include "c_dll_wrapper.h"
2
#include "base_class.h"
3
#include <windows.h>
4
5
   DLLIMPORT base* create_base(double x_in)
6
   {
7
      return new base(x_in);
8
   }
9
10
   DLLIMPORT void set_x(base* LV_ref, double x_in)
11
   {
12
      LV_ref->set_x(x_in);
13
   }
14
15
   DLLIMPORT void get_x(base* LV_ref, double* x_out)
16
   {
17
      LV_ref->get_x(x_out);
18
   }
19
20
   DLLIMPORT void destroy_base(base* LV_ref)
21
   {
22
      delete LV_ref;
23
   }
24
25
   DLLIMPORT void sqr_x(base* LV_ref)
26
   {
27
      LV_ref->sqr_x();
28
   }

Das Import an sich ist kein Problem.
Nun wie soll ich den cluster initialisieren?
warum ist das value zb. von der sqr_x() VI NULL ?

Bitte seh Anhang.

von Okocha (Gast)


Lesenswert?

Mein Problem ist, dass der LV_ref immer gleich NULL.
zb. bei dieses Funktion:
1
DLLIMPORT base* create_base(double x_in)
2
{
3
  return new base(x_in);
4
}
wird das Objekt erzeugt.

so weit so gut
Wenn ich aber dieses VI set_x() bzw. dieses Funktion:
1
DLLIMPORT void set_x(base* LV_ref, double x_in)
2
{
3
  LV_ref->set_x(x_in);
4
}
ist dann das PointValue von LV_ref wieder Null.

von Hans (Gast)


Lesenswert?

Benutzen Sie eine globale Variable und keinen Cluster. Dann sollte es 
klappen

von Dietmar (Gast)


Lesenswert?

Der Rückgabewert von createbase ist ein Zeiger. Dieser Zeiger MUSS als 
Wert an die get und set Funktionen übergeben werden! Als 1. Parameter.

Hierzu muss der anstelle des Clusters wieder ein U32 Wert verwendet 
werden. Dann sollte das funktionieren. Mischen von Datentypen U32 und 
Cluster ist hier nicht die Lösung ;-)

Wieso soll der gültige "c" Zeder überhaupt von LV verwaltet werden? LV 
kann damit nix, aber auch garnix anfangen.

Verwalte den Zeiger da wo er benötigt wird, in der wrapper DLL.

von Okocha (Gast)


Lesenswert?

Dietmar schrieb:
> Der Rückgabewert von createbase ist ein Zeiger. Dieser Zeiger MUSS als
> Wert an die get und set Funktionen übergeben werden! Als 1. Parameter.

--> Wo soll ich das tun auf C++ Seite in dem ich zb. bei set:
1
DLLIMPORT void set_x(base* LV_ref, double x_in)
2
{
3
  LV_ref = create_base(double x_in);  
4
  LV_ref->set_x(x_in);
5
}
 // es ist unschön da muss ich mehr mals LV_ref erzeugen ob das GUT IST?

 schreibe oder auf Labview Seite "Das weiss es nicht wie das geht: Soll 
ich die Labview library verwenden wie MoveBlock?"

von physiker (Gast)


Lesenswert?

Okocha schrieb:
> // es ist unschön da muss ich mehr mals LV_ref erzeugen ob das GUT IST?

Warum denn das? Du kannst z.B. in Deinem Wrapper eine globale Variable 
vom base* haben, der von create_base(double x_in) ein Wert zugewiesen 
wird und auf den alle anderen zugreifen. Das ganze kannst Du natürlich 
noch ein bisschen absichern, um sicher zu gehen, daß create_base bereits 
aufgerufen wurde und nur einmal aufgerufen wird. Wenn es nur eine 
Instanz geben soll, kannst Du Dir create_base auch ganz sparen und Dein 
Wrapper erledigt das automatisch.

von Okocha (Gast)


Lesenswert?

physiker schrieb:
> Warum denn das? Du kannst z.B. in Deinem Wrapper eine globale Variable
> vom base* haben, der von create_base(double x_in) ein Wert zugewiesen
> wird und auf den alle anderen zugreifen. Das ganze kannst Du natürlich
> noch ein bisschen absichern, um sicher zu gehen, daß create_base bereits
> aufgerufen wurde und nur einmal aufgerufen wird.


Sorry
Ich muss wieder fragen:
Soll ich diese Globale Variable in der Wrapper schon tun?
So in der Art:
1
base* static_Var = NULL;
2
[\code]
3
und dann innerhalb der create_base(double x_in) so:
4
[code]
5
DLLIMPORT base* create_base(double x_in)
6
{
7
  static_Var = new base(x_in);
8
  return static_Var;
9
}

von Simon (Gast)


Lesenswert?

Was ist das?
Nein
Du muss nicht so machen und wie ist mit dem Objekt LV_ref?

von Okocha (Gast)


Lesenswert?

Ehrlich gesagt weiss es nit .....
Danke

von Dietmar (Gast)


Lesenswert?

Also,

in dem VI getbase hast du einen U32 als Wert der aus der Wrapper DLL 
geliefert wird. Das ist ein Zeiger, den generierst du ja in der DLL in 
dem du die Funktion "createbase aufrufst.

--> DLLIMPORT base* create_base(double x_in) in deinem VI heist das Ding 
ja "function return"

Das kann man so machen.

Das VI set_x benötigt nun genau diesen Wert. Du hast in dem VI einen 
Cluster als Übergabeparameter angegeben "LV_ref". Diesen Cluster musst 
du nun durch einen U32 ersetzen. Das musst du in dem Konfiguration voin 
dem DLL aufruf machen.

Dann wird die "function return" mit dem neuen U32 Datentypen im 
create_x.. verbunden. Damit hat nun die Funktion in der Wrapper DLL 
einen gültigen Zeiger auf die abgeleitete Klasse und kann auf die 
Elemente der KLasse zugreifen. Nun sollte keine NULL mehr zurück kommen.

Der ganze Code in der Wrapper ist eh kritisch, da nicht auf gültige 
Zeiger kontrolliert wird.

Du kannst froh sein wenn dir dein System nicht komplett abstürzt und du 
nur eine Schutzverletzung gemeldet bekommst.

Wenn du die Änderungen gemacht hast, zeig doch bitte mal das 
Blockdiagramm mit Sequenz create_base - get_x - destroy_base


Btw: soclhe Stielblüten machen das lesen von Sourcecode nicht einfacher 
;-)
Rein oder raus, aber nicht reinraus
#define DLLIMPORT __declspec (dllexport)

Gruß Dietmar

von Okocha (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Dietmar,


anbei meine Änderung.
Es lauft nicht wie gewünscht weiss es nicht was ich verbockt habe.

Ich bekomme immer eine Fehlermeldung seh bitte Anhang.


Sorrrrrrrrrrrrrrrrrrrrrrrrrrryyyyyyyyyyyy

von Dietmar (Gast)


Angehängte Dateien:

Lesenswert?

Ich meinte eigentlich das Blockdiagram von den zusammenhängenden VI's. 
VI's einzeln aufrufen geht nicht. Sollte dann so aussehen wie oben.

Leider kann ich deine DLL hier nicht öffnen, habe nicht das neueste 
Visual Studio hier laufen. Du hast eine Debug Version angehängt. Die 
benötigt die Redistributables von M.

von Dietmar (Gast)


Lesenswert?

Eine Frage noch: Was ist das Ziel deiner Übung?

Willst du eine DLL erstellen um C-Code in Labview zugänglich zu machen?
Hast du eine bestehende DLL und willst auf diese zugreifen?

Wenn ja, hast du den Header der DLL? Eine Wrapper ist eigentlich nur 
dann nötig wenn deine DLL wild mit Zeigern hantiert, da hat LV ein 
Problem mit. Ansonsten kannst du dir den Wrapper sparen und direkt auf 
die exportierten Funktionen zugreifen. Kannst du ggf. den Header 
hiereinstellen oder weitere Infos zugänglich machen?

Im Augenblick sieht es so aus als wenn du auf mehreren baustellen 
gleichzeitig arbeitest.

von Okocha (Gast)


Lesenswert?

Dietmar schrieb:
> Eine Frage noch: Was ist das Ziel deiner Übung?
>
Ziel meine Übung ist eine bestehende DLL in Labview zu importieren.

> Willst du eine DLL erstellen um C-Code in Labview zugänglich zu machen?
ja habe ich schon gemacht.
> Hast du eine bestehende DLL und willst auf diese zugreifen?
ja habe ich auch erstellt.
>
> Wenn ja, hast du den Header der DLL?
ja
>Eine Wrapper ist eigentlich nur
> dann nötig wenn deine DLL wild mit Zeigern hantiert, da hat LV ein
> Problem mit. Ansonsten kannst du dir den Wrapper sparen und direkt auf
> die exportierten Funktionen zugreifen. Kannst du ggf. den Header
> hiereinstellen oder weitere Infos zugänglich machen?
>
ja
> Im Augenblick sieht es so aus als wenn du auf mehreren baustellen
> gleichzeitig arbeitest.


Ich danke es dir für die grosse Hilfe

von Okocha (Gast)


Lesenswert?

Hallo Dietmar,


in meine erste C_Wrapper habe ich einen Fehler gemacht.
Ich habe nicht den "base * LV_ref" als Parameter weitergegeben.
Die C_Wrapper ist dann so in der Art geschrieben:

Heaeder Anteil:
1
   DLLIMPORT base* create_base(double x_in);
2
   DLLIMPORT void set_x(double x_in);
3
   DLLIMPORT void get_x(double* x_out);
4
   DLLIMPORT void destroy_base();
5
   DLLIMPORT void sqr_x();

   CPP Teil:

1
   base* StaticObject = NULL;
2
   
3
     DLLIMPORT base* create_base(double x_in)
4
     {
5
     return new base(x_in);
6
     }
7
     .......

 und natürlich habe ich dann keine Terminals und ist auch nicht die 
schlauste Idee

von Okocha (Gast)


Lesenswert?

Hallo Dietmar,

noch einen kurze Frage:
Soll für meinen richtigen Projekt einen State Machine aufbauen?

von Dietmar (Gast)


Lesenswert?

Hast du den Zugriff jetzt fehlerfrei laufen?

Ob du eine Statemachine aufbaust oder nicht hängt von deiner Anwendung 
ab. Zwingend notwendig ist das nicht.

von Okocha (Gast)


Lesenswert?

Dietmar schrieb:
> Hast du den Zugriff jetzt fehlerfrei laufen?
ja
Ich habe keine Abstürze mehr.

Ich bin immer noch erstaunt was man mit Labview machen kann.

von Okocha (Gast)


Lesenswert?

Hallo Dietma,


ich habe eine kurze Frage.
Ich habe einen state machine mit labview erstellt.
Allerdigns ohne Vi destroy_base einzusetzen.
Wann soll ich das einsetzen ohne labview abtürzen zu lassen?


Danke

von Dietmar (Gast)


Lesenswert?

Spät gesehen,

du solltest dir in deiner Statemachine einen state schaffen in dem du 
aufräumst, hier auch das VI destroy_base aufrufen. Danach darfst du halt 
nicht mehr auf die DLL zugreifen.

Danach solltest du das VI mit der Statemachine auch beenden. Eigentlich 
darf dann keine Fehlermeldung mehr kommen.

Gruß
Dietmar

von Okocha (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Dietmar,


danke für die Antwort.
Ich habe auch in der Statemachine einen state erstellt, wo ich halt nur 
das VI destory_base aufrufe.
Sobald ich dieses state aufrufe stürtz Labview ab.
Bitte seh Anhang.



Danke in voraus

von Okocha (Gast)


Lesenswert?

Hallo,


Das Labview Abstürz bekomme ich nicht immer.
Ich weiss es nicht woran es liegen kann.
Das Problem lässt sich nicht reproduzieren.
Es tritt ein aber halt nicht immer.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.