DLL Datei ersetzen funktioniert nicht bei Programmstart?



  • 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);
    }
    


  • audacia schrieb:

    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.

    Wenn ich meine DLL Statisch einbinde, dann funktioniert das mit dem String.
    Wirklich seltsam...



  • audacia schrieb:

    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.

    Wenn ich meine DLL Statisch einbinde, dann funktioniert das mit dem String.
    Wirklich seltsam...

    Edit: Sry wegen doppel Post, der Server hing bei mir.



  • Nein, tut es nicht. Es kann sein, daß der Memory-Manager sich dann etwas anders verhält und sich zufällig für Lazy Deallocation entscheidet, so daß der Puffer noch zugreifbar, obgleich bereits freigegeben ist.

    Nur weil etwas zufällig funktioniert, muß es noch längst nicht der richtige Weg sein. Was ich oben schrieb, hat weiterhin Gültigkeit. Lies und verstehe es.



  • audacia schrieb:

    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

    Auszug aus einer der großen STL-Implementierungen:

    <a href= schrieb:

    Dinkumware">
    basic_string::c_str

    const value_type *c_str() const;

    The member function returns a pointer to a non-modifiable C string constructed by adding a terminating null element (value_type()) to the controlled sequence. Calling any non-const member function for *this can invalidate the pointer.

    Und auch der Standard ist imho eindeutig...

    Auszug aus dem Standard Draft schrieb:

    21.3.6 - basic_string string operations [lib.string.ops]

    const charT* c_str() const;

    -1- Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements equal the corresponding elements of the string controlled by *this and whose last element is a null character specified by charT().

    -2- Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the returned value as a valid pointer value after any subsequent call to a non-const member function of the class basic_string that designates the same object as this.

    const charT* data() const;

    -3- Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first size() elements equal the corresponding elements of the string controlled by *this. If size() is zero, the member returns a non-null pointer that is copyable and can have zero added to it.

    -4- Requires: The program shall not alter any of the values stored in the character array. Nor shall the program treat the returned value as a valid pointer value after any subsequent call to a non- const member function of basic_string that designates the same object as this.

    allocator_type get_allocator() const;

    -5- Returns: a copy of the Allocator object used to construct the string.

    P.S.: Auch wenn ich durchaus weiß das der C++ Builder und const so seine Probleme haben... z.B. Das eine TDateTime const & geändert werden kann u.a.

    cu André



  • asc schrieb:

    Auszug aus einer der großen STL-Implementierungen:

    Vielleicht ist dir ja aufgefallen, daß ich nicht den Standard-String, sondern System::String benutzt habe.

    Und daß es mit std::[w]string so nicht geht, ebenso auch, wie es trotzdem machbar ist, hatte ich oben schon geschrieben. Wenigstens dir hätte ich zugetraut, daß du meine Posts genau liest, bevor du Einspruch erhebst 😉

    asc schrieb:

    P.S.: Auch wenn ich durchaus weiß das der C++ Builder und const so seine Probleme haben... z.B. Das eine TDateTime const & geändert werden kann u.a.

    Damit hat das nichts zu tun; außerdem ist das eigentlich seit C++Builder 2007 kein Thema mehr (falls doch, bitte ich um Beispiel zwecks Bugreport).



  • audacia schrieb:

    asc schrieb:

    P.S.: Auch wenn ich durchaus weiß das der C++ Builder und const so seine Probleme haben... z.B. Das eine TDateTime const & geändert werden kann u.a.

    Damit hat das nichts zu tun; außerdem ist das eigentlich seit C++Builder 2007 kein Thema mehr (falls doch, bitte ich um Beispiel zwecks Bugreport).

    Es ist zumindestens beim C++Builder 2007 (und sofern ich mich nicht irre hatte ich es auch unter 2009 nachgetestet) noch aktuell, und ja, es existiert ein Bugreport.

    Und das mit dem Stringtyp habe ich tatsächlich überlesen, auch wenn ich es weiterhin als gefährlich ansehe, und eher als Mangel der const-correctness bei den VCL-Klassen betrachte (die ja - da aus Delphi kommend - recht wenig mit const am Hut haben). Grundsätzlich würde ich Konstrukte wo ich auf Implementationsdetails der VCL zurückgreifen muss eher meiden.

    cu André



  • asc schrieb:

    Und das mit dem Stringtyp habe ich tatsächlich überlesen, auch wenn ich es weiterhin als gefährlich ansehe, und eher als Mangel der const-correctness bei den VCL-Klassen betrachte (die ja - da aus Delphi kommend - recht wenig mit const am Hut haben). Grundsätzlich würde ich Konstrukte wo ich auf Implementationsdetails der VCL zurückgreifen muss eher meiden.

    Gefährlich wäre es nur, wenn System::String eine Implementation von std::basic_string<> wäre. Dieser Zusammenhang besteht jedoch in keiner Weise; vielmehr ist System::String nur ein Wrapper für den Delphi-String-Typen (demnach keine VCL-Klasse, sondern das Äquivalent eines Delphi-Intrinsic!).

    String::c_str(), dessen Namensgebung nur eine Konzession an 1997 bereits etablierte C++-Gewohnheiten war, gab seit jeher einen nicht konstanten Zeiger zurück. Das vereinfacht die Verwendung des Strings in Zusammenhängen wie dem von mir demonstrierten, insbesondere, da der Delphi-String und mithin auch System::String aus historischen Gründen ab 1 indiziert werden (in Delphi 1 für 16-Bit-Windows waren Strings auf 255 Zeichen begrenzt, und die Länge wurde bei Index 0 gespeichert). Demnach wäre übrigens auch &myBasicString[0] äquivalent zu &myDelphiString[1] - ein weiterer, hoffentlich hinreichend deutlicher Hinweis darauf, wie gering der Verwandtschaftsgrad der beiden String-Typen ist.



  • audacia schrieb:

    Demnach wäre übrigens auch &myBasicString[0] äquivalent zu &myDelphiString[1] - ein weiterer, hoffentlich hinreichend deutlicher Hinweis darauf, wie gering der Verwandtschaftsgrad der beiden String-Typen ist.

    Ich bin dennoch der Meinung das man nicht gegen die Implementierungsdetails einer Bibliothek hin entwickeln sollte. Wer sagt das die Implementierung des Stringtyps (bei gleichbleibender Schnittstelle) sich nicht irgendwann ändert?



  • asc schrieb:

    Ich bin dennoch der Meinung das man nicht gegen die Implementierungsdetails einer Bibliothek hin entwickeln sollte. Wer sagt das die Implementierung des Stringtyps (bei gleichbleibender Schnittstelle) sich nicht irgendwann ändert?

    Du siehst den Rückgabetyp einer sichtbaren Funktion als Implementierungsdetail an?



  • audacia schrieb:

    Du siehst den Rückgabetyp einer sichtbaren Funktion als Implementierungsdetail an?

    Bei den VCL spezifischen Bereichen schon, da diese niemals auf const correctness hin entwickelt wurden, und du hier einen internen Buffer bekommst. Ich sehe hier die Modifikation tatsächlich als sehr Problematisch an.


Anmelden zum Antworten