Labview DLL Import

Gast #4324744
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.
Angehängte Dateien:
Gast #4325196
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.
Gast #4325639
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.
Gast #4325746
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?"
Gast #4325800
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.
Gast #4325988
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
}
Gast #4326069
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
Gast #4326487
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.
Angehängte Dateien:
Gast #4326509
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.
Gast #4326545
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
Gast #4326582
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
Gast #4330966
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
Gast #4338876
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren