DLL Datei ersetzen funktioniert nicht bei Programmstart?
-
Hallo,
ich habe in meinem Programm eine funktion eingebaut, um Updates automatisch herunterzuladen.Jetzt habe ich da aber ein problem da die DLL Datei genau so heißt wie diese wo in meinem Programm Ordner ist und kann sie leider nicht ersetzen lassen, da mein Programm ja geöffnet ist.
Gibt es irgendeine möglichkeit die DLL Datei in meinem Programm freizustellen?
Weil mein Programm scheint noch auf diese DLL Datei zuzugreifen.Edit: Mit FreeLibrary() kann ich meine DLL Datei nicht freigeben, ich habe meine DLL über Projekt->Dem Projekt hinzufügen die Lib Datei von der DLL hinzugefügt.
Nur wie kann ich die DLL freigeben, wenn mein Programm noch läuft?Ich bedanke mich schonmal für die Hilfe.
MfG
-
Die DLL dynamisch laden anstatt statisch. Dann kannst du auch Freelibrary benutzen.
-
Danke.
Ich weiss, aber ich finde das am einfachsten die DLL Datei Statisch zu laden.
Naja, wenn es nicht anders geht, dann werde ich sie wohl Dynamisch laden müssen.
Vielen Dank für die antwort.
MfG
-
Hallo nochmal,
ich bekomme immer eine Fehlermeldung "Zugriffs verletzung"
ab und zu funktioniert das.Sobald ich das hier aufrufe
void __fastcall TForm1::Button1Click(TObject *Sender) { HINSTANCE h = LoadLibrary("Version.dll"); typedef String __stdcall TVersion(); TVersion* Version = (TVersion*)GetProcAddress(h,"_Version"); String Test = Version(); Memo1->Text = Test; FreeLibrary(h); }
erhalte ich folgende fehlermeldung:
Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000.Was habe ich falsch gemacht?`
Vielen Danke schonmal.
MfG
-
Hast du auch das "Version" in der DLL Exportiert? Wenn die DLL Statisch geladen wird muss man das glaub ich nicht machen, bei einer dynamischen DLL allerdings schon. (benutze allerdings selbst nur dynamische DLLs).
Und lass bei "Version" den Unterstrich weg und schau dann ob es dann geht.
Die Schutzverletung kommt wohl daher, dass wohl der Export nicht existiert.
-
Man sollte das dll_Handle und bei Erfolg auch den importierten Funktionspointer erst auf 0 testen bevor man ihn verwendet.
-
Braunstein schrieb:
Man sollte das dll_Handle und bei Erfolg auch den importierten Funktionspointer erst auf 0 testen bevor man ihn verwendet.
Und vielleicht mal den Debugger benutzen - dann merkt man das auch selbst.
-
Vielen Dank für die antworten.
@Maverick Die funktion habe ich natürlich in der DLL Datei exportiert.
Und beim Funktionsaufruf habe ich mal den Unterstrich weg gelassen, funktionierte auch nicht.Hier die DLL Datei:
#include <vcl.h> #include <windows.h> #include <IdHTTP.hpp> #pragma hdrstop //--------------------------------------------------------------------------- extern "C" __declspec(dllexport)String Version(); #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } //--------------------------------------------------------------------------- String Version() { return "Test..."; }
Vieleicht rufe ich die Funktion einfach falsch auf, sry, ich arbeite noch nicht so lange mit DLLs.
Wo liegt denn jetzt eigentlich das Problem?
Danke euch schonmal.
Edit: Ich hab mal überprüft ob h > 0 ist:
typedef String __stdcall TVersion(); HINSTANCE h = LoadLibrary("Version.dll"); if (h) { TVersion* Version = (TVersion*)GetProcAddress(h,"_Version"); String Test = Version(); Version1->Caption = Test; FreeLibrary(h); }
Ich habe die Funktion jetzt 2 mal aufgerufen und das hat geklappt, beim 3ten mal bekam ich diese Meldung:
ScreenUnd wenn ich auf Schließen Klicke und erneut aufrufe, dann wird die Funktion aufgerufen u.s.w.
Aber wieso bekomme ich immer nach dem 2ten aufruf der Funktion eine CPU Meldung?MfG
-
Hallo
Sieh die mal die Doku von LoadLibrary und GetProcAdress in der MSDN an, da steht auch jeweils wie man aus den Rückgabewerten der Funktionen die jeweiligen Fehlerbeschreibungen bekommt, die die helfen den Fehler einzugrenzen.
Außerdem gibt es verschiedene externe Tools mit denem man eine fertige DLL untersuchen kann auf die extertierten Symbole. Da siehst du wie deine Funktion wirklich heißt.Was mir an deinem Quellcode aus der DLL auffällt ist das du die Funktion Version mit dem Typ "String" versehen hast. Das ist aber nicht kompatibel zu "extern C", da Klassen nicht in einer C-Schnittstelle abbildbar sind.
bis bald
akari
-
akari schrieb:
Was mir an deinem Quellcode aus der DLL auffällt ist das du die Funktion Version mit dem Typ "String" versehen hast. Das ist aber nicht kompatibel zu "extern C", da Klassen nicht in einer C-Schnittstelle abbildbar sind.
Es ist kein Problem, einer als extern "C" deklarierten Funktion C++-Typen als Parameter zu übergeben. extern "C" beeinflußt nur die Dekoration des Funktionsnamens.
In DLL-Interfaces dürfen trotzdem keine nicht-POD-Typen verwendet werden; der Grund ist, daß für C++-Spezifika wie VMT-Layout, RTTI, Destruktorparameter und dergleichen kein binärer Standard existiert und darüber hinaus mehrere Module möglicherweise verschiedene Memory-Manager verwenden.
-
Vielen Danke.
Was kann ich statt "extern C" benutzen?
Hier auf der Seite gabs ja ein Tutorial über DLLs, leider habe ich den Link nicht mehr.
Es wäre sehr nett wenn ihn mir einer Posten könnt.
MfG
-
Du kannst extern "C" schon lassen. Du solltest nur keinen String zurückgeben. Statt dessen bietet sich z.Bsp. const char* an.
Hier ist der dll-Tutorial-Link
http://bcb-tutorial.c-plusplus.net/DLL_Tutorial/index.html
-
Braunstein schrieb:
Du solltest nur keinen String zurückgeben. Statt dessen bietet sich z.Bsp. const char* an.
Das geht natürlich nur, wenn du ein Stringliteral zurückgibst. Ansonsten hast du entweder ein Speicherleck (wenn du den Rückgabewert mit new oder malloc allozierst) oder eine Zugriffsverletzung (wenn du z.B. den Rückgabewert der c_str()-Methode eines lokalen Strings zurückgibst).
Wenn du über ein C-Interface einen String zuückgeben willst, bleibt dir wenig anderes als der Weg, der bei den meisten Windows-API-Funktionen gegangen wird:
/* * int GetAString (Char* buf, unsigned nchars); * * Description: * Returns a string. * * Parameters: * buf - The buffer where the string is to be stored. May be 0. * nchars - The size of the buffer, in units of sizeof (Char). * * Return value: * If the call succeeded, the operation returns the number of * characters written to the buffer, not including the trailing * null character. * If the return value is greater than the buffer size, the * returned value indicates the amount of characters required * to hold the resulting string. * If the operation failed, the return value is zero. */ extern "C" __declspec (dllexport) int GetAString (Char* buf, unsigned nchars) { String s = ...; if (<operation failed>) return 0; if (buf && (nchars > 0)) { unsigned cccnt = std::min <unsigned> (s.Length (), nchars - 1); std::memcpy (buf, s.c_str (), sizeof (Char) * cccnt); buf[cccnt] = '\0'; } return s.Length (); }
Benutzung so:
void foo (void) { String s; s.SetLength (200); unsigned len = GetAString (s.c_str (), s.Length () + 1 /* including '\0' */); if (len > s.Length ()) // more than 200 characters { s.SetLength (len); GetAString (s.c_str (), len + 1); } }
-
Danke euch.
Gibt es eine möglichkteit mehrstellige Zeichenkonstante im Char abzulegen?
z.B. const char[100]?Ich habe das mal so versucht:
extern "C" __declspec(dllexport) const char Version() { return 'Version......'; }
Ich will mir das ganze nicht so kompliziert machen, wegen eine Funktion, deswegen möchte ich wissen, ob ich mehr Zeichen im char ablegen kann.
Edit: Ich habs jetzt mal so gemacht:
extern "C" __declspec(dllexport) const char* Version() { return "Version....."; }
Das funktioniert, hab bis jetzt noch keine Fehlermeldung bekommen, beim aufrufen der Funktion.
Ich hoffe, das man das so lassen kann.Vielen Dank für eure Hilfe.
MfG
-
Hallo nochmal,
ich habe folgendes mal versucht:String Titel2(String URL) { TIdHTTP *IdHTTP1; IdHTTP1 = new TIdHTTP(0); String Quelltext; String Title; IdHTTP1->Request->UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; Quelltext = IdHTTP1->Get(URL); Title = Quelltext.SubString(Quelltext.Pos("<title>")+7,Quelltext.Pos("</title>")-Quelltext.Pos("<title>")-7); IdHTTP1->Free(); return Title.c_str(); } extern "C" __declspec(dllexport) const char* Titel(String URL) { const char* Text = Titel2(URL).c_str(); return Text; }
Irgendwie klappt das mit der Rückgabewert nicht, wenn ich statt
return Text;
diese Rückgabewert schreibe
**return "Teesstt";**dann funktionierts.Das mit der Rückgabewert Text, funktioniert nicht, ich bekomme immer diese meldung Zugriffsverletzung, das nervt langsam.
Wieso meckert er bei externe Zugriff?
Wenn ich es direkt in C++ Consolen Anwendung ausführe, funktioniert es perfekt.Ich versuche schon mehrere Stunden diesen Fehler zu beheben, aber leider ohne erfolg und im Forum finde ich auch nix passendes, was mein Problem lösen könnte.
Ich wäre euch sehr dankbar, wenn einer diesen Code zum laufen bringen könnte.
Achja, ich lasse von bestimmten Internet Seiten den Quelltext auslesen und Kopiere mir dann den Titel, nur weiss ich nicht, wie ich es extern aufrufen kann, ohne immer diese Zugriffsverletzung zu bekommen.
MfG
-
bruce85 schrieb:
Ich versuche schon mehrere Stunden diesen Fehler zu beheben, aber leider ohne erfolg und im Forum finde ich auch nix passendes, was mein Problem lösen könnte.
Du suchst bereits mehrere Stunden und bist unfähig, im Forum eine Lösung zu finden - obgleich sie sich im selben Thread einen Post vor deinem befindet?
Ich habe erklärt, warum es mit Zeichenkettenliteralen funktioniert, du aber für alle anderen Fälle eine Zugriffsverletzung bekommst. Ich habe erklärt, warum man keine Objekte zwischen verschiedenen Modulen herumreichen darf, ohne Vorkehrungen getroffen zu haben. Ich habe erklärt, wie man dennoch einen String zurückgibt, und ich habe dir sogar ausführlichen und lauffähigen Beispielcode gegeben. Daß du es dennoch schaffst, das alles rundweg zu ignorieren, spricht nicht eben für deine kommunikative Befähigung.
-
Hallo
Diese Zugriffsverletzung ist genau das wovor audacia schon gewarnt hat. Deine zweite Variante geht eben nicht, da du einen Zeiger auf einen Speicherbereich zurückgibst der von einer lokalen Variable gehalten wird. Nachdem die Funktion beendet ist ist der Speicherbereich nicht mehr gültig, jeder Zugriff über die Adresse im Zeiger führt potentiel zu einer Speicherverletzung!
Also lies dir nochmal die die letzen Posts von audacia und Braunstein durch, dort werden Ursache und Lösung erklärt.
Und wenn du das umständlich findest : ja das ist es, genauso wie die WinAPI selber. Es gibt aber keine bessere Lösung für C-Interfaces.
bis bald
akari
-
audacia schrieb:
Das geht natürlich nur, wenn du ein Stringliteral zurückgibst. Ansonsten hast du entweder ein Speicherleck (wenn du den Rückgabewert mit new oder malloc allozierst) oder eine Zugriffsverletzung (wenn du z.B. den Rückgabewert der c_str()-Methode eines lokalen Strings zurückgibst).
Es geht auch ohne Stringliterale Speicherlecks und Zugriffsverletzungen zu vermeiden. Man muss nur etwas Sorgfalt walten lassen und den Speicherbereich nicht zu zeitig freigeben sowie nach Freigabe der dll nicht mehr darauf zugreifen.
Bei deinem Beispielcode schreibst du in const char* Bereiche von String-Variablen, was so auch nicht zulässig ist. Wenn schon, dann würde ich hier new und delete bemühen.
-
Braunstein schrieb:
Es geht auch ohne Stringliterale Speicherlecks und Zugriffsverletzungen zu vermeiden. Man muss nur etwas Sorgfalt walten lassen und den Speicherbereich nicht zu zeitig freigeben sowie nach Freigabe der dll nicht mehr darauf zugreifen.
Da wäre ich sehr gespannt, wie du das sauber lösen wolltest.
Braunstein schrieb:
Bei deinem Beispielcode schreibst du in const char* Bereiche von String-Variablen, was so auch nicht zulässig ist. Wenn schon, dann würde ich hier new und delete bemühen.
Wieso sollte das nicht zulässig sein?
String::c_str() gibt keinen const-Zeiger zurück:// ustring.h, l.144 wchar_t* __fastcall c_str() const { return (Data)? Data: const_cast<wchar_t*>(L"");}
Und wenn man nicht c_str() verwenden kann (z.B. in std::string), so nehme man einfach &string[0].
-
Eine kleine Korrektur muß ich noch anbringen, und zwar in der Benutzung der Beispielfunktion:
void foo (void) { String s; s.SetLength (200); unsigned len = GetAString (s.c_str (), s.Length () + 1 /* including '\0' */); s.SetLength (len); // <-- sollte unkonditionell ausgeführt werden if (len > s.Length ()) // more than 200 characters GetAString (s.c_str (), len + 1); }