Ich bin in der DLL Hell :-(
-
@Braunstein:
Dein Vorschlag scheint zu funktionieren, ich muss vermutlich nicht von vorne beginnen!Die .dll mit deinen zwei Funktionen hat compiliert.
Ich habe bei meinem VS-Projekt wo ich die .dll aufrufe jetzt das .h File eingebunden und folgendes programmiert:#include "MyDLL.h" typedef MyDllClass (*PGET_MYDLLCLASS); PGET_MYDLLCLASS GetMyClass; . . . GetMyClass = (PGET_MYDLLCLASS)::GetProcAddress(hDll, "get_myclass"); // Cool, jetzt habe ich einen Pointer auf meine dll klasseEine kleine Frage ist jedoch noch offen:
Q: Wenn GetMyClass jetzt ein Pointer auf die Klasse in meiner dll ist warum funktioniert dann der -> operator nicht? (ich habe GetMyClass->GetData(); oder auch MyDllClass * pDll = GetMyClass; probiert)DANKE
Mario
-
Du hast jetzt lediglich eine Funktion, die dir einen Pointer auf deine Klasse liefern kann.
Du mußt dann also so etwas machen.GetMyClass = (PGET_MYDLLCLASS)::GetProcAddress(hDll, "_get_myclass"); FreeMyClass = (PFREE_MYDLLCLASS)::GetProcAddress(hDll, "_free_myclass"); MyClass *my = GetMyClass(); // dann mit my arbeiten ... // zum Schluß nicht vergessen FreeMyClass(my);Bitte vergess auch die Fehlerbehandlung (testen auf Nullpointer) nach GetProcAddress nicht.
-
Du hast natürlich wieder recht:
MyClass *my = GetMyClass();
funktioniert!Wenn ich jetzt MyClass-> schreibe kommt das Menü mit allen Methoden der Klasse.
....nur...
egal welche Methode ich aufrufen will, ich bekomme immer einen:
error LNK2001: unresovled external symbol......
fatal error LNK1120: 1 unresolved externals... dabei bin ich schon so nahe am Ziel

-
Ist die cpp, in der die Definition deiner Klasse steht mit in die dll gelinkt?
-
Noch was:
Die Funktionen deiner Klasse sollten als Parameter nur POD-Typen (also char, int etc.) bzw. Pointer enthalten. Bei Übergaben von Klassen per Referenz kann es zu Problemen mit unterschiedlichen Bibliotheksimplementationen kommen.
Ich hatte da mal ein Problem mit einer Referenz auf std::string zwischen BCB5 und 6.
-
Ich bin der Meinung, dass mein .cpp File passt, es geht ja unter Borland, nur unter VS nicht.....
Mein .h File enthält eigentlich keine besonderen, außer selbst definierte, Typen:
#ifndef ENCODER_H #define ENCODER_H #define READ_TEMP 0 #define READ_ADC 3 #define SIUSIZE 4 #define OTPSIZE 4 #define SSISIZE 3 #define FESIZE 8 #define I2C_SIU 0x01 #define I2C_FE 0x02 #define I2C_ALSD 0x04 #define I2C_CORDIC 0x08 #define I2C_OFFSET 0x10 #define I2C_AGC 0x20 #define I2C_SYSTEM 0x40 //--------------------------------------------------------------------------- /** Error-codes used as return values for the usb-interfacing. */ typedef enum { ERROR_NO_ERR, /**< No error occured. */ ERROR_CMD_FAILED, /**< The uC encoutered an error. */ ERROR_CANNOT_CONNECT, /**< The demoboard is probably not plugged in. */ ERROR_NO_CONN, /**< Transfer function was called on a closed connection */ ERROR_TRANSMIT, /**< An error occured during the transmission of a command. */ ERROR_RECEIVE, /**< An error occured during receiption. */ ERROR_ILLEGAL_ARGUMENTS, /**< The arguments are out of bounds. */ ERROR_GENERIC /**< An unspecified error occured. */ } UsbComError; typedef enum {FRONTEND, ALSD, CORDIC, OFFSET, AUTOGC, SYSTEM, SIU } I2cReg; typedef enum {AS5040, AS5043, AS5045} EncoderType; typedef enum {RED, GREEN, YELLOW} EncoderState; typedef struct I2cRegisters{ unsigned char siu[SIUSIZE]; unsigned char hsfe[FESIZE]; unsigned char alsd[1]; unsigned char cordic[3]; unsigned char cordicState[1]; unsigned char offset_comp[3]; unsigned char autogc[1]; unsigned char system[1]; } sI2cData; typedef struct EncoderData{ unsigned char otp[OTPSIZE]; unsigned char ssi[SSISIZE]; sI2cData i2c; unsigned int position; unsigned char magnitude; int sin; int cos; int ch0; int ch1; } sEncoderData; //class __declspec(dllexport) __stdcall Encoder{ class Encoder{ private: sEncoderData mData; bool IsAGCEnabled; bool IsMagCompEn; bool IsExternal; EncoderType type; EncoderState state; void SetEncoderType(EncoderType dev); public: Encoder(); EncoderType GetEncoderType(); bool IsConnected(); UsbComError Connect(const EncoderType dev); UsbComError Disconnect(); sI2cData ReadI2C(unsigned char regList); void ReadOTP(); double GetAngle(); unsigned int GetPosition(); void SetOTPByte(const unsigned char val, const unsigned char& byteNum); char GetOTPByte(const unsigned char byteNum); unsigned int ReadSSI(); unsigned char GetSSIByte(unsigned char num); char GetI2CByte(I2cReg reg, unsigned char byteNum); void SetI2CByte(I2cReg reg, unsigned char val, unsigned char byteNum = 0); int GetSIN(); int GetCOS(); int GetCh0(); int GetCh1(); unsigned char GetAGC(); void SetAGC(unsigned char val); void DisableAGC(); void EnableAGC(); bool GetAGCState(); unsigned char GetCordicState(); // just with AS5040 bool IsExternalEncoder(); void EnableExternalEncoder(); void EnableOnboardEncoder(); unsigned char GetMag(); double GetADCChannel(unsigned char ch); UsbComError Zapp(); EncoderState GetState(); }; #endifIm .cpp habe ich dann: (das ist nur ein Auszug aus dem File)
#include "Encoder.h" USEFILE("Encoder.h"); //--------------------------------------------------------------------------- UsbConnection mUsbCon; bool WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved) { return 1; } //--------------------------------------------------------------------------- extern "C" __declspec(dllexport) double GetDllVersion(void){ return 1.0; } extern "C" __declspec(dllexport) Encoder * GetEncoder(){ Encoder * pEnc = new Encoder; return pEnc; } extern "C" __declspec(dllexport) void FreeEncoder(Encoder * enc){ delete enc; } /////////////////////////////////////////////////////////////////////////////// // Constructor // /////////////////////////////////////////////////////////////////////////////// Encoder::Encoder(){ IsAGCEnabled = true; IsExternal = false; IsMagCompEn = false; type = AS5043; } . . . // usw....
-
Kann es sein, dass jetzt die Methoden innerhalb der Klasse dekoriert sind?
Der genaue Fehler lautet nämlich:
error LNK2001 unresolved external symbol .... "Encoder::GetCh0(void)" ?GetCh0@Encoder@@$$FQSDF...Das schaut aus wie das Problem, dass ich vor dem extern "C" gehabt habe. Nur jetzt innerhalb der Methode.
-
Lass das USEFILE mal weg.
Nur als Hinweis. Bei Deklarationen von enums, structs oder Klassen brauchst du kein typedef.
statttypedef enum {RED, GREEN, YELLOW} EncoderState;das hier
enum EncoderState {RED, GREEN, YELLOW};Genau so bei struct. Das ist aber kein Fehler.
Dei Problem besteht wohl darin, das der Kompiler nach inkludieren der Header auch die Definitionen deiner Klassenfunktionen sehen will. Da wirst du wohl nicht drumrumkommen die schon erwähnte Wrapperklasse zu schreiben oder statisch zu linken.
-
Hier mal ein Bsp. für so eine Wrapperklasse. Ist gekürzt.
class TChart2DForm; typedef const char* Tget_version(); // for TChartForm typedef TChart2DForm * Tget_chart(); typedef void Tfree_chart(TChart2DForm *&); typedef bool Tshow_file(TChart2DForm * ch, const char* fname); class TPostProcDll { private: bool loadDll() { hdll = LoadLibrary(DllPath.c_str()); if( hdll == 0 ) return false; Fget_chart = reinterpret_cast<Tget_chart*>(GetProcAddress(hdll, "_get_chart")); if( Fget_chart == NULL ) return false; Ffree_chart = reinterpret_cast<Tfree_chart*>(GetProcAddress(hdll, "_free_chart")); if( Ffree_chart == NULL ) return false; Fshow_file = reinterpret_cast<Tshow_file*>(GetProcAddress(hdll, "_show_file")); if( Fshow_file == NULL ) return false; Fget_version = reinterpret_cast<Tget_version*>(GetProcAddress(hdll, "_get_version")); if( Fget_version == NULL ) return false; return true; } bool loadFreeFunct() { hdll = LoadLibrary(DllPath.c_str()); if( hdll == 0 ) return false; Ffree_chart = reinterpret_cast<Tfree_chart*>(GetProcAddress(hdll, "_free_chart")); if( Ffree_chart == NULL ) return false; return true; } public: TPostProcDll(const char* dllpath = "") : Fget_version(0), Fget_chart(0), Ffree_chart(0), Fshow_file(0), DllPath(dllpath), m_chart(0), hdll(0) { if( DllPath.empty()) DllPath = "Postprocdll.dll"; } ~TPostProcDll() { if( hdll != 0) { Ffree_chart(m_chart); FreeLibrary(hdll); } } bool showFile(const char* fname) { if( hdll == 0 && !loadDll()) return false; if( m_chart == NULL ) m_chart = Fget_chart(); if( !Fshow_file(m_chart, fname)) return false; return true; }; const char* getVersion() { if( hdll == 0 && !loadDll()) return ""; return Fget_version(); } private: std::string DllPath; TChart2DForm * m_chart; HINSTANCE hdll; Tget_version* Fget_version; Tget_chart* Fget_chart; Tfree_chart* Ffree_chart; Tshow_file* Fshow_file; };die cpp
//--------------------------------------------------------------------------- #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } //--------------------------------------------------------------------------- const char* Version = "1.0.1"; namespace DELPHIN_POSTPROC { extern "C" __declspec(dllexport) TChart2DForm * get_chart() { TChart2DForm *chart = new TChart2DForm(NULL); return chart; } //--------------------------------------------------------------------------- extern "C" __declspec(dllexport) const char* get_version() { return Version; } //--------------------------------------------------------------------------- extern "C" __declspec(dllexport) void free_chart(TChart2DForm *& ch) { delete ch; ch = NULL; } //--------------------------------------------------------------------------- extern "C" __declspec(dllexport) bool show_file(TChart2DForm * ch, const char* fname) { TStringList *list = new TStringList; list->Add(fname); DimOutp::TDIMReadError res = ch->ShowChart(list, true, false, PostProcCallBacks()); delete list; if( res != DimOutp::NoError) { return false; } return true; } //---------------------------------------------------------------------------Das ist ein Beispiel von mir, also stör dich nicht an den Namen. Hier muß man dann nur die oben genannte Headerdatei einbinden, die Wrapperklasse im Hauptprogramm instanziieren und schon gehts (zumindest bei mir
).
-
Danke für deinen Input mit den enums. Ich kenne sonst keine Programmierer daher sind solche Hinweise für mich sehr wertvoll.
Da die Schnittstelle meiner .dll jetzt nur aus 3 Funktionen besteht werde ich versuchen sie statisch zu linken.
Mal schauen ob das geht. An meiner .dll muss ich da ja nichts ändern.
Ich werde dich auf dem Laufenden halten.
Danke,
Mario