Problem mit Programm und DLL



  • Hi,

    Habe ein Problem mit meinem Programm und der dazugehörigen DLL. Und weis nicht waran es liegt.

    Das Programm soll den inhalt von RichEdit an eine DLL senden und die Konvertiert das dann. Aber das funktioniert nicht. Ist auch noch eine Funktion die die Version der DLL angibt und die funktioniert.

    DLL erstellen geht ohne Probleme!
    Bekomme die Meldung beim erstellen des Programms:

    [Linker Fehler] Unresolved external 'TMainForm::Base64Encod(System::AnsiString)' referenced from D:\C++\TESTS\NEU PROJEKT\ROMAIN.OBJ

    Ich Poste mal den Code.

    // Aus dem Progamm die *.CPP Datei
    
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Romain.h"
    #include "KonverterDLL.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TMainForm *MainForm;
    //---------------------------------------------------------------------------
    __fastcall TMainForm::TMainForm(TComponent* Owner)
            : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::SpeedButton5Click(TObject *Sender)
    {
     Version();
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::SpeedButton1Click(TObject *Sender)
    {
      Base64Encod(RichEdit1->Text);
    }
    //---------------------------------------------------------------------------
    
    // Aus dem Progamm die Header Datei
    
    //---------------------------------------------------------------------------
    #ifndef RomainH
    #define RomainH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <Buttons.hpp>
    #include <ComCtrls.hpp>
    //---------------------------------------------------------------------------
    class TMainForm : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
            TRichEdit *RichEdit1;
            TSpeedButton *SpeedButton1;
            TSpeedButton *SpeedButton5;
            void __fastcall SpeedButton1Click(TObject *Sender);
            void __fastcall SpeedButton5Click(TObject *Sender);
    private:	// Anwender-Deklarationen
     AnsiString Base64Encod(AnsiString slToEnc);
     AnsiString Base64Decod(AnsiString slToDec);
     AnsiString CTWordEncod(AnsiString slToEnc);
     AnsiString CTWordDecod(AnsiString slToDec);
    public:		// Anwender-Deklarationen
            __fastcall TMainForm(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TMainForm *MainForm;
    //---------------------------------------------------------------------------
    #endif
    
    // Aus der Programm die *.CPP Datei
    
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #include "KonverterDLL.h"
    #include "Romain.h"
    #include <math.h>
    #include <windows.h>
    #pragma hdrstop
    //---------------------------------------------------------------------------
    AnsiString TMainForm::Base64Encod(AnsiString slToEnc)
    {
      //Base64-Tabelle besteht aus 64 druckbaren Zeichen:
      const char Base64Table[64]=
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      char * buftoenc = slToEnc.c_str();
      int bufsize = slToEnc.Length() + 1;
      char * encbuf = new char[slToEnc.Length() * 5];
      encbuf[0] = '\0';  int ilStrLen = -1;
      int i=0; int b64byte[5];
      unsigned char *buftemp;
      AnsiString slRetVal = EmptyStr;
    
      //Speicher für den temporären String reservieren:
      buftemp=(unsigned char *)malloc(bufsize+2);
      strcpy(buftemp,buftoenc);
      if (fmod(bufsize,3)==1)
      {
        buftemp[bufsize]='\0';
        buftemp[bufsize+1]='\0';
      }
      if (fmod(bufsize,3)==2)buftemp[bufsize]='\0';
      while (i<bufsize)
      {
        b64byte[0]=buftemp[i]>>2;
        b64byte[1]=((buftemp[i]&3)<<4)|(buftemp[i+1]>>4);
        b64byte[2]=((buftemp[i+1]&0x0F)<<2)|(buftemp[i+2]>>6);
        b64byte[3]=buftemp[i+2]&0x3F;
        encbuf[i+(i/3)]=Base64Table[b64byte[0]];
        encbuf[i+(i/3)+1]=Base64Table[b64byte[1]];
        encbuf[i+(i/3)+2]=Base64Table[b64byte[2]];
        encbuf[i+(i/3)+3]=Base64Table[b64byte[3]];
        i+=3;
      }
      free(buftemp);
      if (fmod(bufsize,3)==0) ilStrLen = bufsize*8/6;
      else if (fmod(bufsize,3)==1) ilStrLen = ((bufsize+2)*8/6)-2;
      else if (fmod(bufsize,3)==2) ilStrLen = ((bufsize+1)*8/6)-1;
      else ilStrLen = -1;
      if(ilStrLen > 0) slRetVal = AnsiString(encbuf).SubString(1, ilStrLen);
      if(encbuf != NULL) { delete encbuf; encbuf = NULL; }
      MainForm->RichEdit1->Text = slRetVal;
      return slRetVal;
    }
    //---------------------------------------------------------------------------
    void Version()
    {
     MessageBox ( NULL, "Version: v1.0.0.0 Beta", "Konverter DLL", MB_OK );
    }
    //---------------------------------------------------------------------------
    #pragma argsused
    int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
    {
            return 1;
    }
    //---------------------------------------------------------------------------
    
    // Aus der DLL die Header Datei
    
    #ifdef __BUILDING_THE_DLL
    #define __EXPORT_TYPE __export
    #else
    #define __EXPORT_TYPE __import
    #endif
    AnsiString Base64Encod(AnsiString slToEnc);
    AnsiString Base64Decod(AnsiString slToDec);
    AnsiString CTWordEncod(AnsiString slToEnc);
    AnsiString CTWordDecod(AnsiString slToDec);
    void __EXPORT_TYPE Version();
    


  • Weiß den keiner warum das nicht geht???



  • So wie es aussieht hast Du da die ganzen Funktionen durcheinandergebracht. Wenn Du nicht weiß wie man mit Dlls arbeitet lese am besten http://www.fachinformatiker-ihk.de/download/extras/Alle_Programme_mit_PDFArtikel.zip
    Da ist alles ordentlich beschrieben wie man Dlls unter BCB verwendet und erstellt.



  • Was sagt dir denn der #define __Export_Type ?



  • SilentSurfer schrieb:

    Was sagt dir denn der #define __Export_Type ?

    Weiß es nicht. Ist aus einem Beispiel aus der BCB Hilfe. Meine erste DLL die ich erstelle.



  • OK,
    nur kurz:
    Du exportierst aus deiner Dll nur diese Versionfunktion. Die Anweisung dafür hast du ja selber hingeschrieben.
    Die anderen Funktionen sind nicht exportiert worden, weil kein _EXPORT_TYPE vorangestellt ist.
    Logischerweise kann sie der Linker dann auch nicht finden.



  • Und nicht nur das. Auch die Funktionen, die Exportiert werden sollten sind Methoden von TMainForm (Darf nicht sein, wenn es Funktionen aus der Dll sein sollen). Und die Implementation von AnsiString TMainForm::Base64Encod() ist in der dll, aber der Kommentar ganz oben lügt (trotz des Grammatikfehlers).



  • Hier ist jetzt der neue DLL Header. Aber der Fehler kommt immer noch.

    #ifdef __BUILDING_THE_DLL
    #define __EXPORT_TYPE __export
    #else
    #define __EXPORT_TYPE __import
    #endif
    AnsiString __EXPORT_TYPE Base64Encod(AnsiString slToEnc);
    AnsiString __EXPORT_TYPE Base64Decod(AnsiString slToDec);
    AnsiString __EXPORT_TYPE CTWordEncod(AnsiString slToEnc);
    AnsiString __EXPORT_TYPE CTWordDecod(AnsiString slToDec);
    void __EXPORT_TYPE Version();
    

    @bIce Verstehe nicht genau was du meinst 😕



  • Ich hab jetzt angepasst wie das ungefähr aussehen könnte. Es kann aber sein, dass ich einen Fehler eingebaut habe.
    Zunächst die Dll:
    Die Header-Datei: (muss auch von der Cpp-Datei der Exe inkludiert werden).

    // Aus der DLL die Header Datei 
    
    #ifdef __BUILDING_THE_DLL 
    #define __EXPORT_TYPE __declspec(dllexport) 
    #else 
    #define __EXPORT_TYPE __declspec(dllimport)
    #endif 
    __EXPORT_TYPE char * Base64Encod(char * slToEnc); 
    __EXPORT_TYPE char * Base64Decod(char * slToDec); 
    __EXPORT_TYPE char * CTWordEncod(char * slToEnc); 
    __EXPORT_TYPE char * CTWordDecod(char * slToDec); 
    __EXPORT_TYPE void Version();
    
    // AnsiString sollte man nicht verwenden, damit es etwas portabler ist.
    

    Die Cpp-Datei:

    // Aus der Dll die *.CPP Datei 
    
    //--------------------------------------------------------------------------- 
    #include <vcl.h> 
    
    // Damit die Funktionen exportiert werden. 
    //- Muss auf jedenfall vor dem Inkludieren des 
    //- Dll-Headers aufgerufen werden.
    #define __BUILDING_THE_DLL 
    
    #include "KonverterDLL.h" 
    
    #include "Romain.h" 
    #include <math.h> 
    #include <windows.h> 
    #pragma hdrstop 
    //--------------------------------------------------------------------------- 
    char * Base64Encod(char * slToEnc)
    {
     //TODO: Implementieren
    }
    //--------------------------------------------------------------------------- 
    char * Base64Decod(char * slToDec); 
    {
      //TODO: Implementieren
    }
    //--------------------------------------------------------------------------- 
    char * CTWordEncod(char * slToEnc); 
    {
      //TODO: Implementieren
    }
    //--------------------------------------------------------------------------- 
    char * CTWordDecod(char * slToDec); 
    {
      //TODO: Implementieren
    }
    //--------------------------------------------------------------------------- 
    void Version()
    {
     MessageBox ( NULL, "Version: v1.0.0.0 Beta", "Konverter DLL", MB_OK ); 
    }
    //--------------------------------------------------------------------------- 
    #pragma argsused 
    int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) 
    { 
            return 1; 
    } 
    //---------------------------------------------------------------------------
    

    Jetzt die Exe:
    Zum Projekt der Exe musst Du auch noch die *.lib-Datei der Dll hinzufügen.

    header-Datei:

    // Aus dem Progamm die Header Datei 
    
    //--------------------------------------------------------------------------- 
    #ifndef RomainH 
    #define RomainH 
    //--------------------------------------------------------------------------- 
    #include <Classes.hpp> 
    #include <Controls.hpp> 
    #include <StdCtrls.hpp> 
    #include <Forms.hpp> 
    #include <Buttons.hpp> 
    #include <ComCtrls.hpp> 
    //--------------------------------------------------------------------------- 
    class TMainForm : public TForm 
    { 
    __published:    // Von der IDE verwaltete Komponenten 
            TRichEdit *RichEdit1; 
            TSpeedButton *SpeedButton1; 
            TSpeedButton *SpeedButton5; 
            void __fastcall SpeedButton1Click(TObject *Sender); 
            void __fastcall SpeedButton5Click(TObject *Sender); 
    private:    // Anwender-Deklarationen 
    public:        // Anwender-Deklarationen 
            __fastcall TMainForm(TComponent* Owner); 
    }; 
    //--------------------------------------------------------------------------- 
    extern PACKAGE TMainForm *MainForm; 
    //--------------------------------------------------------------------------- 
    #endif
    

    Und die Cpp-Datei

    // Aus dem Progamm die *.CPP Datei 
    
    //--------------------------------------------------------------------------- 
    #include <vcl.h> 
    #pragma hdrstop 
    
    #include "Romain.h" 
    #include "KonverterDLL.h" 
    //--------------------------------------------------------------------------- 
    #pragma package(smart_init) 
    #pragma resource "*.dfm" 
    TMainForm *MainForm; 
    //--------------------------------------------------------------------------- 
    __fastcall TMainForm::TMainForm(TComponent* Owner) 
            : TForm(Owner) 
    { 
    } 
    //--------------------------------------------------------------------------- 
    void __fastcall TMainForm::SpeedButton5Click(TObject *Sender) 
    { 
     Version(); 
    } 
    //--------------------------------------------------------------------------- 
    void __fastcall TMainForm::SpeedButton1Click(TObject *Sender) 
    { 
      Base64Encod( RichEdit1->Text.c_str() ); 
    } 
    //---------------------------------------------------------------------------
    

    EDIT: Ein paar Fehler beseitigt



  • Danke soweit geht das jetzt.
    Bekomme aber noch einen Fehler! Wenn ich mit dem Programm Konvertiere. Bekomme ich den Fehler "Ungültige Zeigeropeation." Aber Funktionieren tut alles und den Konvertierten Text bekomme ich auch zurück. Aber wie bekomme ich diese Fehlermeldung weg???



  • Wo kommt den der Fehler? Und wie lässt es sich kompilieren, wenn ein Fehler auftaucht? Oder ist es eine Warnung?



  • Der Fehler kommt wenn ich im Programm auf den Button klicke.

    Wenn ich dies aus der DLL raus nehme kommt der Fehler nicht mehr. Aber die funktion ist damit auch weg.

    return slRetVal;
    


  • Liegt es evtl. daran, das du mit

    return slRetVal;
    

    einen AnsiString zurückgibst, obwohl der Rückgabewert in char* geändert wurde?



  • SilentSurfer schrieb:

    Liegt es evtl. daran, das du mit

    return slRetVal;
    

    einen AnsiString zurückgibst, obwohl der Rückgabewert in char* geändert wurde?

    Nein, habe den Rückgabewert wieder in AnsiString geändert und es geht auch nicht.



  • Hast du schon mit

    return slRetVal.c_str();
    

    versucht?



  • bIce schrieb:

    Hast du schon mit

    return slRetVal.c_str();
    

    versucht?

    Ja, dann habe ich den Fehler auch noch. Aber nicht mehr bei jedem mal. Seltsam 😕



  • anfänger_sos schrieb:

    bIce schrieb:

    Hast du schon mit

    return slRetVal.c_str();
    

    versucht?

    Ja, dann habe ich den Fehler auch noch. Aber nicht mehr bei jedem mal. Seltsam 😕

    Nicht so seltsam. Die Problematik von c_str() wurde meines Wissens hier schon
    einige Male erörtert und man findet dazu auch einige Anmerkungen in der Hilfe.
    Die Kernaussage ist, daß genau die obige Verwendung zu Problemen führen kann.
    Deklariere Dir eine Variable, kopiere den Wert auf den c_str() verweist dort
    hinein (vorheriges Speicher allokieren nicht vergessen) und gib diese Variable
    zurück.

    Gruß,

    Alexander



  • hmm,

    Deklariere Dir eine Variable, kopiere den Wert auf den c_str() verweist dort
    hinein (vorheriges Speicher allokieren nicht vergessen) und gib diese Variable
    zurück.

    Ich verstehe nicht wie das gemeint ist.



  • So mache ich das für gewöhnlich. Ob das der beste und einfachste Weg ist,
    weiß ich nicht, aber bei mir funktioniert er.

    char* cResult = new char[slRetVal.Length()+1]; // Speicher allokieren
       strcpy(cResult, slRetVal.c_str()); // String kopieren
    

    Dieser Code steht übrigens auch in der BCB-Hilfe.
    Such mal nach AnsiString c_str() (Beispiel).
    Da steht auch ein Fall (der Deinem Fall ähnelt), bei dem es Probleme
    geben könnte.

    Gruß,

    Alexander



  • Danke.
    Aber der Fehler kommt leider immer noch.



  • anfänger_sos schrieb:

    Aber der Fehler kommt leider immer noch.

    Jedesmal oder nur ab und zu?
    Und welche Fehlermeldung?

    Gruß,

    Alexander


Anmelden zum Antworten