DLL Funktion aus externer DLL einbinden zur Laufzeit
-
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-FunktionenVon 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 ichLIBRARY 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 ; ZipProgressWas 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.
Alsotypedef 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.dllEs 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.dllHoffe 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...