DLL Funktion aus externer DLL einbinden zur Laufzeit



  • Hallo,
    ich lese nun seit Stunden hier sämtliche DLL Beiträge, dazu Internet (Google)
    und bekomme es einfach nicht richtig hin:

    ZIP Datei: sevZip32.dll (liegt mit im Programmordner)

    In der main.cpp habe ich bei Auswahl eines Menüs (Datensicherung) folgendes stehen:

    void __fastcall TForm1::Datensicherung1Click(TObject *Sender)
    {AnsiString z1,ZipKey;Boolean o1;                                               // Vars definieren
     z1=PrgPfad+"sevZip32.dll.dll";                                                 // Zip-Dateiname mit Pfad
    
     HINSTANCE ZipDll; ZipDll=LoadLibrary(z1.c_str());                              // DLL Laden
     if(ZipDll!=0) {                                                                // Laden der DLL hat nicht funktioniert
      ShowMessage("ZIP-Dll >sevZip32.dll< kann nicht geladen werden!?\r\rDie ZIP-Funktionen stehen nicht zur Verfügung.");
     }                                                                              // ende if(ZipDll
     else {                                                                         // DLL wurde geladen
      ShowMessage("ZIP-DLL erfolgreich geladen");                                   // Info geben
      ZipKey=ReverseString("1234-5678-1234-5678");                                  // Key für sevZip32.dll (ist gespiegelt)
    
      void (__stdcall* ZipInit)(String);                                            //
      ZipInit         =(void(__stdcall*)(String)) GetProcAddress(ZipDll,"_InitZIP");// ZIP DLL initialisieren
    
      void (__stdcall* ZipLanguage)(int);                                             //
      ZipLanguage     =(void(__stdcall*)(int))  GetProcAddress(ZipDll,"_SetLanguage");// ZIP DLL Sprache setzen
      void (__stdcall* ZipCompression)(int);                                          //
      ZipCompression  =(void(__stdcall*)(int))  GetProcAddress(ZipDll,"_SetCompressionRate");// ZIP DLL Compressionsrate einstellen
      void (__stdcall* ZipAddFile)(int);                                              //
      ZipAddFile       =(void(__stdcall*)(int)) GetProcAddress(ZipDll,"_ZipAddFile"); // ZIP DLL File mitpacken
      void (__stdcall* ZipCancel)();                                                  //
      ZipCancel        =(void(__stdcall*)())    GetProcAddress(ZipDll,"_CancelZip");  // ZIP DLL Funktion abbrechen
      void (__stdcall* ZipFolderLocation)(int);                                       //
      ZipFolderLocation=(void(__stdcall*)(int)) GetProcAddress(ZipDll,"_SaveFolderLocation"); // ZIP DLL Welchen Pfad pro Datei mitsichern (leer=mit vollem Pfad zippen)
    
      o1=ZipInit(ZipKey);                                                           // initialisieren
      if(o1==false) {                                                               // nicht ok
       ShowMessage("ZIP-Funktionen können nicht initialisiert werden!?");           // Info geben
       return;                                                                      // und raus
      }                                                                             // ende if(o1
    
      ZipLanguage(1);                                                               // Deutsch (1), Englisch (0)
      ZipCompression(6);                                                            // Kompressionsrat 0 (keine)....9(langsam!), 6 = Standard
      ZipFolderLocation("");                                                        // kompletten Pfad immer mitsichern
    
    // ... hier das ZIPPEN noch einbinden
    
      FreeLibrary(ZipDll);                                                          // und DLL wieder freigeben
     }                                                                              // ende else()
    
    }
    

    Im Header der main.cpp habe ich folgendes (erstmal zum Testen nur die
    erste Funktion ZIP Init):

    public:
      typedef bool ZipInit(String pt1);                                              // ZIP DLL Funktion
    

    Bekomme beim Start aber immer die Meldung "Kein zulässiger Typ"
    und der BCB verweist auf die Zeile o1=ZipInit(ZipKey);
    Habe schon alles möglich probiert und bekomme es nicht hin.
    Wo mache ich hier den Denkfehler??? 😕
    Danke für jeden Hinweis; drehe mich scheinbar im Kreis.

    Gruss, Stefan Scholz



  • Was willst du mit dem Typedef? Ist dir klar, dass du in Datensicherung1Click eine lokale Variable hast, die genauso heißt?



  • void (__stdcall* ZipInit) (String);
    

    gehört nicht in die funktion sondern in den header!

    // header myzip.h
    typedef void (*PFUN_ZIPINIT) (String);
    PFUN_ZIPINIT ZipInit;
    //... weitere
    
    // deine main.cpp
    
    //... lib laden
    HINSTANCE Lib = ::LoadLibrary("ziplib.dll");
    
    if (Lib)
    {
      ZipInit = (PFUN_ZIPINIT) ::GetProcAddress(Lib, "_ZipInit ");
      //... weitere
    }
    

    entweder gehts so, oder das __stdcall fehl noch... weiss grad nicht



  • Habe die Änderungen vorgenommen und erhalte nach wie vor die Meldung mit dem Typ

    im Header Main.h habe ich jetzt:

    public:
      typedef void(*dll_ZipInit) (String);                                           // ZIP DLL Funktion
      dll_ZipInit ZipInit;
     typedef void(*dll_ZipLanguage) (int);                                          // ZIP DLL Funktion
      dll_ZipLanguage ZipLanguage;
    

    In der Main.cpp habe ich jetzt:

    void __fastcall TForm1::Datensicherung1Click(TObject *Sender)
    {AnsiString z1,ZipKey;Boolean o1;                                               // Vars definieren
     z1=PrgPfad+"sevZip32.dll.dll";                                                 // ZIp-Dateiname mit Pfad
    
     HINSTANCE ZipDll=::LoadLibrary(z1.c_str());                                    // DLL Laden
     if(ZipDll!=0) {                                                                // nicht funktioniert
      ShowMessage("ZIP-Dll >sevZip32.dll< kann nicht geladen werden!?\r\rDie ZIP-Funktionen stehen nicht zur Verfügung.");
     }                                                                              // ende if(ZipDll
     else {                                                                         // DLL wurde geladen
      ShowMessage("ZIP-DLL erfolgreich geladen");                                   // Info geben
      ZipKey=ReverseString("1234-56786-1234-5678");                                  // Key für sevZip32.dll (ist gespiegelt)
    
      ZipInit         =(dll_ZipInit)    ::GetProcAddress(ZipDll,"_InitZIP");        // ZIP DLL initialisieren
      ZipLanguage     =(dll_ZipLanguage)::GetProcAddress(ZipDll,"_SetLanguage");    // ZIP DLL Sprache setzen
    
      //void (__stdcall* ZipCompression)(int);                                          //
      //ZipCompression  =(void(__stdcall*)(int))  GetProcAddress(ZipDll,"_SetCompressionRate");// ZIP DLL Compressionsrate einstellen
      //void (__stdcall* ZipAddFile)(int);                                              //
      //ZipAddFile       =(void(__stdcall*)(int)) GetProcAddress(ZipDll,"_ZipAddFile"); // ZIP DLL File mitpacken
      //void (__stdcall* ZipCancel)();                                                  //
      //ZipCancel        =(void(__stdcall*)())    GetProcAddress(ZipDll,"_CancelZip");  // ZIP DLL Funktion abbrechen
      //void (__stdcall* ZipFolderLocation)(int);                                       //
      //ZipFolderLocation=(void(__stdcall*)(int)) GetProcAddress(ZipDll,"_SaveFolderLocation"); // ZIP DLL Welchen Pfad pro Datei mitsichern (leer=mit vollem Pfad zippen)
    
      o1=ZipInit(ZipKey);                                                           // initialisieren
      //void (__stdcall* ZipInit) (ZipKey);
      o1=true;
      if(o1==false) {                                                               // nicht ok
       ShowMessage("ZIP-Funktionen können nicht initialisiert werden!?");           // Info geben
       return;                                                                      // und raus
      }                                                                             // ende if(o1
    
      ZipLanguage(1);                                                               // Deutsch (1), Englisch (0)
      //ZipCompression(6);                                                            // Kompressionsrat 0 (keine)....9(langsam!), 6 = Standard
      //ZipFolderLocation("");                                                        // kompletten Pfad immer mitsichern
    
      FreeLibrary(ZipDll);                                                          // und DLL wieder freigeben
     }                                                                              // ende else()
    
    }
    

    Bitte möglichst genaue Angaben machen; mir ist einfach nicht klar,
    wie die DLL Funktionen eingebunden werden müssen.

    Liegt das Problem vielleicht an der Parameterübergabe String???
    Lass ich das ZipInit weg, meckert er zumindest nicht an den anderen
    3 Aufrufen wie ZipLanguage(1);

    Danke und Gruss, Stefan



  • Hallo,

    Was soll denn das hier:

    o1=ZipInit(ZipKey);
    

    ZipInit ist eine void-Funktion.



  • Hallo, Braunstein

    Ich ging davon aus, daß der Aufruf so korrekt ist (irgendwie muss
    ich doch auch den Rückgabewert o1 (Boolean) erhalten..?
    Wie ist es denn korrekt?

    Wenn ich es im Header so abändere:

    typedef bool(*dll_ZipInit) (String);                                           // ZIP DLL Funktion
      dll_ZipInit ZipInit;
     typedef int(*dll_ZipLanguage) (int);                                          // ZIP DLL Funktion
      dll_ZipLanguage ZipLanguage;
    

    dann erhalte ich bei Aufruf der Menüfunktion
    Zugriffsverletzung bei Adresse 0000000000 ...

    MfG Stefan



  • Ich kenne die Signatur von ZipInit nicht, weiß also nicht was hier korrekt ist. Überprüfst doch bitte mal die Pointer die dir GetProcAddress zurückliefert auf Gültigkeit bevor du die Funktionen aufrufst.
    Was ist eigentlich Boolean bei dir, ein typedef?



  • Hei, Braunstein

    in einer anderen Programmiersprache (GB32) geht die ZIP mit (unter anderem)
    diesen Aufrufen einwandfrei:

    Declare Function InitZip     Lib "sevZip32.dll" _(ByVal sInit As String)   As Boolean   // ZipLanguage 
     Declare Function SetLanguage Lib "sevZip32.dll" _(ByVal nLanguage As Long)              // Zip/Unzip-Funktionen
    

    Von daher weiss ich also, das in der Zip sevZip32.dll die Aufrufe wie InitZip
    mit Rückgabe Boolean (false, true) vorhanden ist und als Übergabeparameter einen String übergebe (bzw. Adresse des String)

    Genau dies möchte ich nun im BCB6 ausführen (siehe Code oben)

    Daher im Header die typedef bool (...) und in der Main.cpp das Laden der DLL und dann mit GetProcAdress() die Funktion definieren. Aber irgendwas fehlt bzw. ist falsch...?

    MfG Stefan



  • z1=PrgPfad+"sevZip32.dll.dll";
    

    müsste das nicht "sevZip32.dll" heißen?



  • Keine Ahnung ob das überhaupt geht. Wer sagt dir denn, dass String in deiner dll identisch mit String (typedef auf AnsiString) beim BCB ist? Schau doch mal mit impdef aus dem BCB\bin-Verzeichnis nach, wie da die Signatur lautet.



  • Hei, @unbekannte
    Danke für den Hinweis mit .dll.dll , ändert aber nix an den Meldungen

    @Braunstein:
    mit impdef erhalte ich

    LIBRARY     SEVZIP32.DLL
    
    EXPORTS
        CancelZip                      @14  ; CancelZip
        InitZip                        @15  ; InitZip
        SaveFolderLocation             @1   ; SaveFolderLocation
        SetCompressionRate             @13  ; SetCompressionRate
        SetLanguage                    @12  ; SetLanguage
        UnZip                          @6   ; UnZip
        UnZipEx                        @4   ; UnZipEx
        ZipAddFile                     @9   ; ZipAddFile
        ZipDeleteFile                  @8   ; ZipDeleteFile
        ZipFile                        @10  ; ZipFile
        ZipFileCount                   @2   ; ZipFileCount
        ZipFileInfo                    @3   ; ZipFileInfo
        ZipFolder                      @7   ; ZipFolder
        ZipFolderEx                    @5   ; ZipFolderEx
        ZipProgress                    @11  ; ZipProgress
    

    Was soll ich daraus erkennen können?

    Der Hersteller der DLL hat z.B. für Borland Delphi folgendes eingetragen:

    Beschreibung
    Bevor Sie die ZIP-Funktionen verwenden können, muss die DLL initialisiert werden. Die Initialisierung erfolgt über die InitZip-Funktion.
    
    Syntax:
    
    LONG InitZip(
      LPCTSTR sInit
    );
    Parameter
      sInit: Gültiger Registrierschlüssel oder Leere Zeichenfolge um die Shareware-Version zu testen. 
    
    Rückgabewert
      TRUE: Initialisierung war erfolgreich 
      FALSE: Initialisierung fehlgeschlagen
    
    { Deklaration der Funktionen }
    { Allgemeine Funktionen }
    function InitZip(sInit: PChar): Integer; stdcall; external 'sevZip32.dll';
    
    procedure SetLanguage(nLanguage: Integer); stdcall; external 'sevZip32.dll';
    

    Verstehe langsam nichts mehr... 😞

    Gruss Stefan



  • Na da hast du doch deine Signatur.
    LPCTSTR entspricht einem const char*. Du kannst den Typ natürlich auch direkt verwenden. Für LONG kannst du long verwenden.
    Also

    typedef long(*dll_ZipInit) (const char*);                                           // ZIP DLL Funktion
    dll_ZipInit ZipInit;
    ZipInit = reinterpret_cast<dll_ZipInit>(::GetProcAddress(ZipDll,"_InitZIP"));
    if( ZipInit == 0 )
    {
    // Fehlerbehandlung
    }
    // und dann später
    o1=ZipInit(ZipKey.c_str());
    

    sollte eigentlich gehen.



  • ...aber jetzt bekomme ich auf ZipInit immer 0 zurück; also

    ZipInit=reinterpret_cast<dll_ZipInit>(::GetProcAddress(ZipDll,"_InitZIP"));
      if(ZipInit==0) {
       FreeLibrary(ZipDll);                                                          // und DLL wieder freigeben
       ShowMessage("Funktion kann nicht deklariert werden!\r\r=> ZipInit");
       return;
      }
    

    bringt Null. ??

    Das hier habe ich in den Public Bereich (Header main.h) reingesetzt:

    public: 
     typedef long(*dll_ZipInit) (const char*);                             // ZIP DLL Funktion
     dll_ZipInit ZipInit;
    

    Also ich kapiere nicht, warum die Einbindung von DLL Funktionen in anderen
    Sprachen wie VBasic, GB32, Delphi usw. wesentlich leichter ist wie scheinbar
    im BCB6 (bin ja erst seit ein paar Wochen umgestiegen).??

    Gruss Stefan



  • Wenn der Pointer 0 ist, hat GetProcAddress die Funktion nicht in der dll gefunden.
    Lass doch mal den Unterstrich vor InitZip in der GetProcAddress weg (werden von ImpDef ja auch nicht angezeigt).



  • Hei,
    nicht der _ war das Problem, sondern der Schreibfehler
    InitZIP statt korrekt InitZip !!! 😃

    Hier eine funktionsfähige Routine für alle verzweifelten DLL-Einbinder:
    DLL ist im Programmpfad (PrgPfad) die Datei: sevZip32.dll

    Es muss KEINE Eintragung im Header gemacht werden; die DLL wird wenn
    benötigt geladen und anschließend wieder freigegeben:

    void __fastcall TForm1::Datensicherung1Click(TObject *Sender)
    {AnsiString z1,ZipKey;Boolean o1;int i1,i2;                                     // Vars definieren
     z1=PrgPfad+"sevZip32.dll";                                                     // ZIp-Dateiname mit Pfad
    
     HINSTANCE ZipDll=::LoadLibrary(z1.c_str());                                    // DLL Laden
     if(ZipDll==0) {                                                                // nicht funktioniert
      ShowMessage("ZIP-Dll >sevZip32.dll< kann nicht geladen werden!?\r\rDie ZIP-Funktionen stehen nicht zur Verfügung.");
     }                                                                              // ende if(ZipDll
     else {                                                                         // DLL wurde geladen
      ShowMessage("ZIP-DLL erfolgreich geladen");                                   // Info geben
      ZipKey=ReverseString("1234-5678-1234-5678");                                  // Key für sevZip32.dll (ist gespiegelt)
    
      typedef bool(*dll_ZipInit)     (const char*);  dll_ZipInit     ZipInit;       // Funktion vorbereiten
      typedef void(*dll_ZipLanguage) (int);          dll_ZipLanguage ZipLanguage;   // Funktion vorbereiten
      typedef  int(*dll_ZipCompress) (int);          dll_ZipCompress ZipCompress;   // Funktion vorbereiten
      typedef void(*dll_ZipLocation) (const char*);  dll_ZipLocation ZipLocation;   // Funktion vorbereiten
      typedef void(*dll_ZipAddFile)  (const char*);  dll_ZipAddFile  ZipAddFile;    // Funktion vorbereiten
    
      ZipInit    =reinterpret_cast<dll_ZipInit>    (::GetProcAddress(ZipDll,"InitZip"));
      if(ZipInit==NULL) {                                                           // Funktion zur Intialisierung nicht gefunden in DLL
       FreeLibrary(ZipDll);                                                         // und DLL wieder freigeben
       ShowMessage("Funktion kann nicht deklariert werden!\r\r=> ZipInit");         // Meldung geben
       return;                                                                      // ende if(ZipInit
      }
                                                                                    // restlichen Funktionen deklarieren
      ZipLanguage=reinterpret_cast<dll_ZipLanguage>(::GetProcAddress(ZipDll,"SetLanguage"));
      ZipCompress=reinterpret_cast<dll_ZipCompress>(::GetProcAddress(ZipDll,"SetCompressionRate"));
      ZipLocation=reinterpret_cast<dll_ZipLocation>(::GetProcAddress(ZipDll,"SaveFolderLocation"));
      ZipAddFile =reinterpret_cast<dll_ZipAddFile> (::GetProcAddress(ZipDll,"ZipAddFile"));
    
      o1=ZipInit(ZipKey.c_str());                                                   // Key initialisieren
      if(o1==false) {                                                               // nicht ok
       ShowMessage("ZIP-Funktion kann mit Key nicht initialisiert werden!?");       // Info geben
       return;                                                                      // und raus
      }                                                                             // ende if(o1
    
      i1=1;i2=6;z1="";                                                              // Vars vorlegen
      ZipLanguage(i1);                                                              // Deutsch (1), Englisch (0)
      ZipCompress(i2);                                                              // Kompressionsrat 0 (keine)....9(langsam!), 6 = Standard
      ZipLocation(z1.c_str());                                                      // kompletten Pfad immer mitsichern  (""=Pfadangaben mit Zippen)
    
      // ... hier jetzt ZIP Funktionen noch ausführen ...//
    
      FreeLibrary(ZipDll);                                                          // und DLL wieder freigeben
     }                                                                              // ende else()
    
    }
    

    Danke, Braunstein für Deine Hilfe!!! 👍
    Gruss Stefan Scholz



  • Den Tipp von Braunstein möchte ich noch ergänzen:

    Zum Aufspüren der Funktionen einer DLL findet man im Ordner

    \cbuilder6\bin\impdef.exe

    Diese muss auf der Shell Ebene (Command) wie folgt aufgerufen werden:

    c:\cbuilder6\bin\> impdef.exe c:\temp\funktionen.def c:\test\sevZip32.dll
    

    Hoffe das hilft vielen weiter ...

    Gruss Stefan



  • Stefan7124 schrieb:

    Es muss KEINE Eintragung im Header gemacht werden; die DLL wird wenn
    benötigt geladen und anschließend wieder freigegeben:

    ARGS... 😡

    so wie du das machst, ist das auf keinen fall zu empfehlen! denn ausserhalb deiner funktionen sind die zip-funktionen dann nicht mehr existent und wenn jemand das nachvollziehen will, hat er ganz schnell wieder ein problem...

    man holt sich auch nicht jedesmal wenn man ne datei zippen will (frag mich schon die ganze zeit, woher die zip.dll ist?) die funktionen wieder neu aus der dll, sondern führt das einmal bei programmstart durch. wenn du das sauber in nen extra-header legst, kannst du das ganze spielend leicht in weiteren projekten wiederverwenden! aber so ist es einfach nur mist!

    und statt eines sinnlosen aufrufes von ReverseString("1234-5678-1234-5678") kannste gleich "8765-4321-8765-4321" schreiben!



  • so wie du das machst, ist das auf keinen fall zu empfehlen! denn ausserhalb deiner funktionen sind die zip-funktionen dann nicht mehr existent
    und wenn jemand das nachvollziehen will, hat er ganz schnell wieder ein problem...
    

    Das sehe ich ein doch anders; die ZIP Funktion wird alle Jubeljahre nur zum zippen gebraucht; wofür soll sie bitte ausserhalb der Funktionen verfügbar sein? Ich brauche sie sonst nirgends. Für einen Newbie ist das Beispiel jedenfalls übersichtlicher als die 'Zerstückelung' in Header, cpp usw. Und das tolle daran: Es funktioniert!

    man holt sich auch nicht jedesmal wenn man ne datei zippen will (frag mich schon die ganze zeit, woher die zip.dll ist?)
    

    Zum Zippen/Entzippen!
    Diese sevZip32.dll ist zu kaufen und ein prima Werkzeug für alle Programmierer...

    die funktionen wieder neu aus der dll, sondern führt das einmal bei programmstart durch. wenn du das sauber in nen extra-header legst, kannst du das ganze
    spielend leicht in weiteren projekten wiederverwenden! aber so ist es einfach nur mist!
    

    Danke für den Kommnetar; wie oben erwähnt wird die Funktion alle Jubeljahre benötigt; von verschwenderischen Speicherbedarf heutiger Programme halte ich nicht viel.
    Übrigens bin ich noch am lernen und daher vielleicht noch nicht soweit wie Du.

    und statt eines sinnlosen aufrufes von ReverseString("1234-5678-1234-5678") kannste gleich "8765-4321-8765-4321" schreiben!
    

    Die Zahlen korrekt reinzuschreiben mag logisch sein, sie in einer EXE Datei als Lizenzcode gedreht reinzuschreiben auch. Es gibt nämlich eine Menge Leute auf diesem Planeten, die nichts besseres zu tun haben, als Lizenzschlüssel zu knacken, auszulesen usw. und nichts ist leichter, als ein Zahlenschlüssel im Reinformat in einer EXE Datei aufzufinden (der obige Schlüssel ist natürlich nicht echt).

    Grüsse Stefan



  • Sunday schrieb:

    so wie du das machst, ist das auf keinen fall zu empfehlen! denn ausserhalb deiner funktionen sind die zip-funktionen dann nicht mehr existent und wenn jemand das nachvollziehen will, hat er ganz schnell wieder ein problem...

    Die Funktionszeiger sind außerhalb auch nicht sichtbar, so dass eigentlich kein Problem entsteht.
    Man könnte das Ganze auch in eine Klasse kapseln. Das Laden der dll dann im Konstruktor oder (besser) beider ersten Verwendung. Das Entlade kann dann im Destruktor erfolgen.
    Dann kann man die Gültigkeit der Funktionen über die Gültigkeit der Klasseninstanz steuern.



  • Stefan7124 schrieb:

    ... Zum Aufspüren der Funktionen einer DLL ...

    bzw. tools wie Dependency Walker verwenden...


Anmelden zum Antworten