c_DLL Wrapper



  • Hallo alle Zusammen,
    ich habe folgende Problem:

    Ich habe einen QT_DLL Bibliothek erstellt.
    In diesem QT_DLL sind unterschiedliche Klassen, die in C++ geschrieben.
    Diesem QT_DLL sollte in Labview eingebunden werden.
    Es ist leider nicht so einfach wie ich das gedacht habe.
    Ich muss einen C_Wrapper schreiben, damit ich in Labview einbinden kann.

    in diesem QT_DLL brauche ich eigentlich bestimmte Funktionen für Labview.
    Ich muss nicht das ganze QT_DLL in C umschreiben.

    hier ist einen Abschnitte von meinem Code:
    --> Hier ist das QT_Dll wie es ist (ohne Änderung)

    #include "Dll_Lib_global.h"
    #include <QObject>
    #include <QString>
    #include <QList>
    #include <QWaitCondition>
    #include <QMutex>
    
    class CPerson;       
    class CSettings;
    class CMandant;      
    class CSensor;       
    class CInit_Settings;
    
    class CMandant
    {
    	....
    
    };
    
    class CSensor
    {
    	public:
    	EFILIBRARY_EXPORT CSensor(CPerson * PPerson);
    	EFILIBRARY_EXPORT CSensor(const CSensor &e) //CopyConstrucor
    	{
    		m_strT1 = e.m_strT1;
    		m_strT2 = e.m_strT2;
    		m_strT3 = e.m_strT3;
    		m_strT4 = e.m_strT4;
    		m_strU = e.m_strU;
    		m_strI = e.m_strI;
    		....
    	}
    	//setter
    	EFILIBRARY_EXPORT void SetT1(QString &str_p) { m_strT1 = str_p;}
    	EFILIBRARY_EXPORT void SetT2(QString &str_p) { m_strT2 = str_p;}
    	EFILIBRARY_EXPORT void SetT3(QString &str_p) { m_strT3 = str_p;}
    	EFILIBRARY_EXPORT void SetT4(QString &str_p) { m_strT4 = str_p;}
    	....
    	//getter
    	EFILIBRARY_EXPORT QString GetT1(void) const { return m_strT1;   }
    	EFILIBRARY_EXPORT QString GetT2(void) const { return m_strT2;   }
    	EFILIBRARY_EXPORT QString GetT3(void) const { return m_strT3;   }
    	EFILIBRARY_EXPORT QString GetT4(void) const { return m_strT4;   }
    	....
    	private:
    		QString m_strT1;
    		QString m_strT2;
    		QString m_strT3;
    		QString m_strT4;
    		....
    };
    
    class Lib: public QObject
    {
    	Q_OBJECT
    	public:
    	EFILIBRARY_EXPORT Lib (bool an_aus, QString &strFileSettings = QString("file.ini"));
    	EFILIBRARY_EXPORT ~Lib();
    	EFILIBRARY_EXPORT QString LibGetVersion();
    	EFILIBRARY_EXPORT QString LibPower(bool boPower);
    	EFILIBRARY_EXPORT CSensor LibSetDefault();
    	......
    
    };
    

    --> hier ist meine C_DLL_Wrapper
    // Header Datei

    //c_DLL_Wrapper // Header File
    #include <QObject>
    #include <QString>
    #include <QList>
    #include <QWaitCondition>
    #include <QMutex>
    
    /* building a DLL */
    #define DLLIMPORT __declspec (dllexport)
    #ifdef __cplusplus
       extern "C" { /* using a C++ compiler */
    #endif
    		typedef struct Lib DLL_Lib;
    		typedef struct CSensor CSensor_wrapper;
    		DLLIMPORT DLL_Lib* create_DLL_Lib(bool an_aus, QString &strFileSettings = QString("file.ini"));
    		DLLIMPORT CSensor_wrapper* createCSensor_wrapper(const CSensor_wrapper &e);
    		DLLIMPORT const char* DLL_LibGetVersion(DLL_Lib* LV_ref);
    		DLLIMPORT const char* DLL_LibPower(DLL_Lib* LV_ref, bool boPower);
    		DLLImport CSensor_wrapper DLL_LibSetDefault(); 
    		...
    		#ifdef __cplusplus
       }
    #endif
    #endif
    

    --> Source Dateien

    //Source Dateien   c_DLL_Wrapper
    #include "c_DLL_Wrapper.h"
    DLLIMPORT DLL_Lib* create_DLL_Lib(bool an_ous, QString &strFileSettings_p)// ToDo QString ist kein C Datentyp
    {
    	return new Lib(an_ous, strFileSettings_p);
    }
    
    DLLIMPORT CSensor_wrapper* createCSensor_wrapper(const CSensor_wrapper &e)
    {
    	return new CSensor(e);
    }
    
    DLLIMPORT const char* DLL_LibGetVersion(DLL_Lib* LV_ref)
    {
    	return LV_ref->LibGetVersion().toUtf8().constData();
    }
    
    DLLIMPORT void DLL_LibPower(DLL_Lib* LV_ref, bool boPower_p)
    {
    	return LV_ref->LibPower(boPower_p);
    }
    
    DLLIMPORT CSensor DLL_LibSetDefault(DLL_Lib* LV_ref)
    {
    	return LV_ref->LibSetDefault();
    }
    //Hier bekomme ich eine Warnung: warning C4190: 'LibSetDefault()'
    //has C-linkage specified, but returns UDT 'CSensor' which is incompatible with C
    

    Danke in voraus



  • meine C_DLL_Wrapper ist nur für diese Classe:

    class Lib: public QObject
    {
        Q_OBJECT
        public:
        EFILIBRARY_EXPORT Lib (bool an_aus, QString &strFileSettings = QString("file.ini"));
        EFILIBRARY_EXPORT ~Lib();
        EFILIBRARY_EXPORT QString LibGetVersion();
        EFILIBRARY_EXPORT QString LibPower(bool boPower);
        EFILIBRARY_EXPORT CSensor LibSetDefault();
        ......
    
    };
    

    Für mich sind nur die Funktionen, die in dieses Klassen sich befinden relevant.



  • Samuel_gast schrieb:

    Danke in voraus

    Wofür? Sehe keine Frage...



  • Sollte es nicht bei deiner letzten Funktion "CSensor_wrapper *" als Rückgabetyp sein?

    Jedoch hast du noch einen großen Fehler drin (und anscheinend nicht verstanden, was ein Wrapper ist): du darfst nicht einfach

    typedef struct CSensor CSensor_wrapper;
    

    schreiben!
    Ein Wrapper bedeutet, daß du eine Struktur erzeugst, welche intern die Daten hält, d.h. z.B.

    struct Sensor_Wrapper
    {
       void *sensor; // intern ein CSensor* !!!
    };
    

    Und aus deiner Wrapper-Header-Datei mußt du natürlich alle C++ Features (d.h. QT, Referenzen, ...) rausnehmen!

    Edit:
    Noch als Hinweis dazu: erstelle dir einfach selber ein C-Projekt, welches dann diese Header-Datei einbindet und deren Funktionen benutzt (ohne Fehler beim Kompilieren zu erzeugen - Linker-Fehler wegen fehlender Implementierung kannst du dann ersteinmal ignorieren).



  • Th69 schrieb:

    Sollte es nicht bei deiner letzten Funktion "CSensor_wrapper *" als Rückgabetyp sein?
    --> ja du hast recht

    DLLIMPORT CSensor_wrapper DLL_LibSetDefault(DLL_Lib* LV_ref)
    {
        return LV_ref->LibSetDefault();
    }
    

    Jedoch hast du noch einen großen Fehler drin (und anscheinend nicht verstanden, was ein Wrapper ist): du darfst nicht einfach

    typedef struct CSensor CSensor_wrapper;
    

    schreiben!
    Ein Wrapper bedeutet, daß du eine Struktur erzeugst, welche intern die Daten hält, d.h. z.B.

    struct Sensor_Wrapper
    {
       void *sensor; // intern ein CSensor* !!!
    };
    

    --> Das habe ich nicht genau verstanden

    Und aus deiner Wrapper-Header-Datei mußt du natürlich alle C++ Features (d.h. QT, Referenzen, ...) rausnehmen!

    Edit:
    Noch als Hinweis dazu: erstelle dir einfach selber ein C-Projekt, welches dann diese Header-Datei einbindet und deren Funktionen benutzt (ohne Fehler beim Kompilieren zu erzeugen - Linker-Fehler wegen fehlender Implementierung kannst du dann ersteinmal ignorieren).



  • Die QT Referenzen habe ich rausgenommen.
    Th69 schrieb:
    Ein Wrapper bedeutet, daß du eine Struktur erzeugst, welche intern die Daten hält, d.h. z.B.

    struct Sensor_Wrapper
    {
       void *sensor; // intern ein CSensor* !!!
    };
    

    Konkret in meinem Code heisst das ich soll eine neu Strctur erzeugen?
    deinem Beispiel habe ich aber leider nicht verstanden 😞



  • Ja, eine neue Struktur in C erzeugen.

    Und dann entsprechend befüllen bzw. auslesen:

    Sensor_Wrapper* create_sensor_wrapper()
    {
      Sensor_Wrapper* sensor_wrapper = new SensorWrapper();
    
      CSensor* sensor = new CSensor(); // <-- hier noch passende Parameter angeben
    
      sensor_wrapper->sensor = static_cast<void *>(sensor);
    
      return sensor_wrapper;
    }
    
    void use_sensor_wrapper(Sensor_Wrapper* sensor_wrapper)
    {
      CSensor* sensor = static_cast<CSensor*>(sensor_wrapper->sensor);
    
      // use sensor...
    }
    

    (und noch ein Freigabefunktion schreiben mit delete)

    Ja, das ist viel Schreibarbeit, aber anders geht es nicht...



  • ist mein struct richtig?

    struct CSensor
    {
    	public:
    	//CSensor(CPerson * PPerson); ist nicht relevant für C_DLL_Wrapper
    	 CSensor(const CSensor &e) //CopyConstrucor
    	{
    		m_strT1 = e.m_strT1;
    		m_strT2 = e.m_strT2;
    		m_strT3 = e.m_strT3;
    		m_strT4 = e.m_strT4;
    		m_strU = e.m_strU;
    		m_strI = e.m_strI;
    		....
    	}
    	//setter
    	 void SetT1(const char* &str_p) { m_strT1 = str_p;}
    	 void SetT2(const char* &str_p) { m_strT2 = str_p;}
    	 void SetT3(const char* &str_p) { m_strT3 = str_p;}
    	 void SetT4(const char* &str_p) { m_strT4 = str_p;}
    	....
    	//getter
    	 const char* GetT1(void) const               { return m_strT1;   }
    	 const char* GetT2(void) const               { return m_strT2;   }
    	 const char* GetT3(void) const               { return m_strT3;   }
    	 const char* GetT4(void) const               { return m_strT4;   }
    	....
    	private:
    		const char* m_strT1;
    		const char* m_strT2;
    		const char* m_strT3;
    		const char* m_strT4;
    		....
    };
    


  • Hallo,

    da hast du aber jetzt wohl meinen Satz mißverstanden. Die Wrapper-Struktur mußt du neu in C erstellen, deine bisherigen C++-Klassen können bleiben wie sie sind.

    Du mußt dann halt nur für die zu exportierenden Klassenfunktionen dafür dann freie Funktionen anbieten (mit der Wrapper-Struktur als (ersten) Parameter und reinen C Parametern, sog. POD).
    Wenn du C++ Datentypen als Parameter durchschleusen willst (z.B. QString), dann mußt du halt auch hierfür einen Wrapper erstellen.

    Mir fällt aber gerade auf, daß ich oben eine Indirektion zu viel drin habe. Besser ist wohl

    Sensor_Wrapper create_sensor_wrapper()
    {
      Sensor_Wrapper sensor_wrapper;
    
      CSensor* sensor = new CSensor(); // <-- hier noch passende Parameter angeben
    
      sensor_wrapper.sensor = static_cast<void *>(sensor);
    
      return sensor_wrapper;
    }
    
    void use_sensor_wrapper(Sensor_Wrapper sensor_wrapper)
    {
      CSensor* sensor = static_cast<CSensor*>(sensor_wrapper.sensor);
    
      // use sensor...
    }
    

    (d.h. Sensor_Wrapper in C direkt verwenden, anstatt als Zeiger)



  • @Th69

    struct Sensor_Wrapper
    {
    void *sensor; // intern ein CSensor* !!!
    };

    Wie definiere ich bitte meine "struct Sensor_Wrapper " anhand meine CSensor class

    class CSensor
    {
        public:
        EFILIBRARY_EXPORT CSensor(CPerson * PPerson);
        EFILIBRARY_EXPORT CSensor(const CSensor &e) //CopyConstrucor
        {
            m_strT1 = e.m_strT1;
            m_strT2 = e.m_strT2;
            m_strT3 = e.m_strT3;
            m_strT4 = e.m_strT4;
            m_strU = e.m_strU;
            m_strI = e.m_strI;
            ....
        }
        //setter
        EFILIBRARY_EXPORT void SetT1(QString &str_p) { m_strT1 = str_p;}
        EFILIBRARY_EXPORT void SetT2(QString &str_p) { m_strT2 = str_p;}
        EFILIBRARY_EXPORT void SetT3(QString &str_p) { m_strT3 = str_p;}
        EFILIBRARY_EXPORT void SetT4(QString &str_p) { m_strT4 = str_p;}
        ....
        //getter
        EFILIBRARY_EXPORT QString GetT1(void) const { return m_strT1;   }
        EFILIBRARY_EXPORT QString GetT2(void) const { return m_strT2;   }
        EFILIBRARY_EXPORT QString GetT3(void) const { return m_strT3;   }
        EFILIBRARY_EXPORT QString GetT4(void) const { return m_strT4;   }
        ....
        private:
            QString m_strT1;
            QString m_strT2;
            QString m_strT3;
            QString m_strT4;
            ....
    };
    

    Sorry 😞



  • Ich habe so gemacht:

    struct Sensor_Wrapper
    {
    	void *Csensor; // intern ein CSensor* !!!
    }; 
    
    Sensor_Wrapper create_sensor_wrapper()
    {
      Sensor_Wrapper sensor_wrapper;
    
      CSensor* sensor = new CSensor(const CEFI_Out &e); // <-- hier noch passende Parameter angeben
    
      sensor_wrapper.Csensor = static_cast<void *>(sensor);
    
      return sensor_wrapper;
    }
    

    Ist das richtig?



  • Ich habe so gemacht:

    struct Sensor_Wrapper
    {
    	void *Csensor; // intern ein CSensor* !!!
    }; 
    
    Sensor_Wrapper create_sensor_wrapper()
    {
      Sensor_Wrapper sensor_wrapper;
    
      CSensor* sensor = new CSensor(const CSensor &e); // <-- hier noch passende Parameter angeben
    
      sensor_wrapper.Csensor = static_cast<void *>(sensor);
    
      return sensor_wrapper;
    }
    

    Ist das richtig?



  • CSensor* sensor = new CSensor(const CSensor &e); // <-- hier noch passende Parameter angeben
    

    Ist das bitte richtig?



  • Wenn du das in den Klammern noch durch einen sinnvollen Wert ersetzt...



  • hier ist meine Version:

    struct Sensor_Wrapper
    {
    	void *Csensor(const CSensor &e); // intern ein CSensor* !!!
    }; 
    
    Sensor_Wrapper create_sensor_wrapper()
    {
      Sensor_Wrapper sensor_wrapper;
    
      CSensor* sensor = new CSensor(const CSensor &e); // <-- hier noch passende Parameter angeben
    
      sensor_wrapper.Csensor = static_cast<void *>(sensor);
    
      return sensor_wrapper;
    }
    


  • Was soll den bitte der Kopierkonstruktor da? Du sollte ersteinmal ein CSensor-Objekt erstellen (bevor du es kopieren kannst).

    Aus deinem ersten Beitrag heraus wohl diesen Konstruktor aufrufen

    CSensor(CPerson * PPerson);
    

    (woher die Person kommt, mußt du natürlich selber wissen - z.B. als Wrapper-Parameter, welche wiederum mittels einer create_person()-Funktion erstellt wurde etc. pp.)

    Nur noch mal als Nachtrag:

    Dies ist deine Wrapper-Struktur (in C):

    struct Sensor_Wrapper
    {
        void *sensor; // intern ein CSensor* !!!
    };
    

    Genau so und nicht anders!!!

    Der void* ist in C nötig, weil C halt keine Klassen kennt (diese aber dann von deinem C++-Code aus als Klasseninstanz interpretiert (gecastet) werden kann.



  • die Klasse CPerson sieht ao aus:

    class CPerson: public CZeit, public CGeld, public CTier
    {
    	public:
    	typedef enum Produkt{ undef, Spezifikation_A, Spezikatation_B, Spezifikation_C} t_Produkt;
    	typedef enum PassendeZeit { SystemStart, SystemPause} t_PassendeZeit;
    	......
    	CPerson(t_Produkt enProdukt = Spezifikation_A, t_Kombination Kombination = testErfolg, t_AsicType asictype = HLM2012 ): CKombination(Kombination),CAsicSort(asictype)
    	{
    		Produkttype(Spezifikation_A);
    		DefaultValues();
    	}
    	CPerson (const CPerson &e, const CKombination &k, const CAsicSort &a): CCAsicSort(a),CKombination(k) 
    	{
    		.....
    
    	}
    	//Getter
    	....
    	// Setter
    	.....
    };
    

    soll ich auf für die eine struct erzeugen?
    Wie mache ich das denn in C, wenn die Klasse CPerson noch von 3 Klassen erbt?


  • Mod

    class CPerson: public CZeit, public CGeld, public CTier
    

    class Zeit: public Geld hätte ich ja noch verstanden, aber das hier? 😮 Du hast Objektorientierung bei Jürgen Wolf gelernt, oder?

    P.S.: CFindest Cdu Cdas Ceigentlich Clesbar?

    P.P.S.: Da du anscheinend nicht der aufmerksamste Leser bist, noch einmal als Klartext: Du hast derzeit ganz andere Probleme, als einen C-Wrapper um eine C++-Klasse zu schreiben.



  • Das habe ich nicht selber programmieren (leider).
    Ich habe einfach die Suppe übernommen.

    SeppJ schrieb:

    class CPerson: public CZeit, public CGeld, public CTier
    

    class Zeit: public Geld hätte ich ja noch verstanden, aber das hier? 😮 Du hast Objektorientierung bei Jürgen Wolf gelernt, oder?

    P.S.: CFindest Cdu Cdas Ceigentlich Clesbar?

    P.P.S.: Da du anscheinend nicht der aufmerksamste Leser bist, noch einmal als Klartext: Du hast derzeit ganz andere Probleme, als einen C-Wrapper um eine C++-Klasse zu schreiben.



  • Hallo,

    Samuel_gast schrieb:

    Wie mache ich das denn in C, wenn die Klasse CPerson noch von 3 Klassen erbt?

    Du scheinst noch nicht (richtig) verstanden zu haben, was ein Wrapper ist?!
    Du brauchst in C keinen Nachbau der C++-Klassen anlegen, sondern du "wrappst" einfach nur einen Zeiger innerhalb einer Struktur (also genauso wie bei dem Sensor-Wrapper)!
    Technisch gesehen könntest du in C auch einfach

    typedef void* Wrapper;
    

    benutzen, aber dann wäre es nicht mehr eindeutig, welcher C++-Typ darin gewrappt wird, also legt man jeweils eine eigene Struktur mit einem "void *" ("void Zeiger") an.

    Puh, langsam weiß ich nicht mehr, wie ich es dir noch näher beschreiben soll...


Anmelden zum Antworten