Geladene Module im Splashscreen



  • Hallo zusammen,

    da meine Anwendung die ich schreibe doch mit der Zeit beträchtlich an Umfang gewinnen könnte, habe ich diese gleich von Anfang an in einzelne Module, sprich DLLs, unterteilt. Im Augenblick habe ich mich für die statische Bindung der DLLs an mein Hauptprogramm entschlossen.
    Nun wollte ich noch, nicht das es eine funktionale Notwendigkeit wäre, einen Splashscreen wärend des Programmstarts anzeigen lassen. Der Splashscreen an sich ist nicht das Problem. Dies wurde ja hier im Forum und auch ausserhalb schon mehr als erschöpfend behandelt.
    Was mich nun noch interessiert, wie erreiche ich es, das ich in dem Splashscreen z.B. die zu meiner Anwendung gehörenden DLLs in der Reihenfolge wie diese geladen werden anzeigen kann. So wie das der z.B. AdobeReader in seinem Eröffnungsbildschirm macht.
    Ich könnte die DLLs ja alle dynamisch selbst laden, allerdings müsste ich dann ja sämtliche DLL-Handles global der gesamten Anwendung verfügbar machen.
    Bei der statischen Bindung werden die DLLs ja zum Programmstart in den Speicher geladen, und beim Fehler einer DLL der Start mit einer Fehlermeldung abgebrochen. Kann man diesen Prozess sozusagen 'Abhören'?
    Würde mich über Anregungen freuen, auch um des lernens willen, um dann mal zu wissen wie soetwas generell gemacht werden kann.

    Grüße Netzschleicher



  • Netzschleicher schrieb:

    Ich könnte die DLLs ja alle dynamisch selbst laden, allerdings müsste ich dann ja sämtliche DLL-Handles global der gesamten Anwendung verfügbar machen.
    Bei der statischen Bindung werden die DLLs ja zum Programmstart in den Speicher geladen, und beim Fehler einer DLL der Start mit einer Fehlermeldung abgebrochen. Kann man diesen Prozess sozusagen 'Abhören'?
    Würde mich über Anregungen freuen, auch um des lernens willen, um dann mal zu wissen wie soetwas generell gemacht werden kann.

    Das Laden von statisch eingebundenen DLLs übernimmt der PE-Loader, und soweit ich weiß, tut er das, bevor dein Programm initialisiert wird, so daß du diesen Prozeß natürlich nicht "abhören" kannst. Du wirst deine DLLs also dynamisch laden müssen (so wie die C++Builder-IDE ihre Packages); wie man das am besten macht, hängt sehr davon ab, wie das Interface zu deinen DLLs aussieht.

    Was exportieren deine DLLs denn? PACKAGE-Klassen, C-Interfaces oder irgendwas Handgestricktes?



  • In den DLLs befinden sich zum Teil weitere Formulare, und auch verwendete Klassen oder einfach Resourcen (z.B. Bitmaps). Das dynamische Laden der DLLs an sich ist auch nicht das Problen. Das funktioniert auch prima. Nur ist eben in dem Fall dann der zugehörige DLL-Handle lokal in der Funktion vorhanden in welcher die dynamische DLL benötigt wird und wird auch dort dann wieder freigegeben.
    Das hatte ich ja angedeutet, das ich ja zum Programmstart alle meine DLLs dynamisch laden und dann ja auch gleich eine Fehlermeldung generieren könnte falls eine DLL fehlt.
    Nur sollten ja globale Variablen vermieden werden, und die Handles wären dann ja solche in gewisser weise. Wo wäre denn der beste Punkt um solch ein dynamisches Laden aller DLLs zu machen? Im Form.Create, oder innerhalb der WINAPI WinMain Funktion?

    Das man den Ladeprozess der statischen DLLs nicht 'Abhören' kann hatte ich schon vermutet, wollte aber doch noch mal nachfragen.



  • Netzschleicher schrieb:

    Nur sollten ja globale Variablen vermieden werden

    Aber nicht um jeden Preis. Es gibt Fälle, da ist eine globale Variable angebracht, und das hier ist einer. Es ist jedenfalls viel sinnvoller, die DLL-Handles global oder in WinMain() zu behalten, als daß du sie dem Hauptformular zuordnest.

    Grundsätzlich würde ich eine Anwendung möglichst so modularisieren, daß alle DLLs sozusagen als Plug-ins eingebunden werden, d.h., daß sie im weitesten Sinne ein vom Hauptprogramm vorgegebenes Interface implementieren, und daß das Hauptprogramm die DLLs gar nicht kennt. Dann mußt du auch keine Globals für das Herumreichen der Handles einführen.



  • OK, wenn das in dem Fall eine Ausnahme der Regel wäre dann könnte ich das ja so machen.
    Nur dann hätte ich wieder eine weitere Frage. Wo plaziere ich am besten die
    Deklaration der DLL-Handles das diese global verfügbar sind? Wenn ich eine extra Header-Datei dafür anlege und diese in die cpp-Datei mit der WINAPI Main und in die cpp-Datei des Formulars includiere bekomme ich eine Linkermeldung das die DLL-Handles in der Objekt-Datei der WINAPI und in der Objekt-Datei des Formulars sozusagen mehrfach definiert werden.



  • Netzschleicher schrieb:

    Nur dann hätte ich wieder eine weitere Frage. Wo plaziere ich am besten die
    Deklaration der DLL-Handles das diese global verfügbar sind? Wenn ich eine extra Header-Datei dafür anlege und diese in die cpp-Datei mit der WINAPI Main und in die cpp-Datei des Formulars includiere bekomme ich eine Linkermeldung das die DLL-Handles in der Objekt-Datei der WINAPI und in der Objekt-Datei des Formulars sozusagen mehrfach definiert werden.

    // Headerdatei
    namespace RuntimeLibraries
    {
    
    extern HMODULE hFirstDll;
    extern HMODULE hSecondDll;
    ...
    
    }
    
      // .cpp-Datei
    namespace RuntimeLibraries
    {
    
    HMODULE hFirstDll;
    HMODULE hSecondDll;
    ...
    
    }
    


  • @audacia

    prima, jetzt hab ichs. Die DLL-Handles sind global verfügbar. Ich werde somit meine DLLs dynamisch laden, was wie ich finde auch den Vorteil hat das ich beim Fehlen einer benötigten DLL auch dann eine für den User verständliche Fehlermeldung erzeugen kann. 🙂

    Allerdings hätte ich jetzt doch noch ein paar weitere Fragen. Oder sollte ich den Tread jetzt hier beenden und einen neuen Aufmachen bezüglich des DLL Handlings?

    Die Fragen wären, wo normalerweise die DLLs geladen werden. Im Augenblick mache ich das im 'OnCreate'-Event des Hauptfensters. Allerdings habe ich auch schon gelesen das in den neueren C++Buildern für vorbereitende Schritte der Kontruktor des Fensters verwendet werden sollte. Gilt dies auch für das Laden von DLLs?

    Und die nächste wäre, ob man dort dann auch gleich mit 'GetProgAdress' sämtliche
    von der jeweiligen DLL exportierten Funktionen holen und auch global verfügbar machen soll, oder dies dann doch erst in der Funktion in welcher diese benötigt werden.

    Die letzte wäre dann, alle DLLs-Handles sollten ja wenn diese nicht mehr gebraucht werden mit 'FreeLibrary()' wieder freigegeben werden. Im Falle des Ladens der DLLs ganz zu Begin würde ich diese dann im 'OnClose'-Event des Fensters wieder freigeben. Oder wäre das in dem Fall nicht nötig, da beim Beenden des Hauptfensters und somit des gesamten Programms sowieso alle Handels gelöscht werden?



  • Netzschleicher schrieb:

    Die Fragen wären, wo normalerweise die DLLs geladen werden. Im Augenblick mache ich das im 'OnCreate'-Event des Hauptfensters. Allerdings habe ich auch schon gelesen das in den neueren C++Buildern für vorbereitende Schritte der Kontruktor des Fensters verwendet werden sollte.

    Daß du statt OnCreate/OnDestroy möglichst Konstruktoren und Destruktoren benutzen sollst, gilt für alle C++Builder-Versionen.

    Netzschleicher schrieb:

    Gilt dies auch für das Laden von DLLs?

    Die haben per se nichts mit dem Hauptformular zu tun und gehören also auch nicht dorthin. Eher nach WinMain(). Man muß allerdings vorsichtig sein, wenn man in der WinMain() herumdoktert, weil C++Builder dort ja auch Code einfügt und verändert (statische Formular-Initialisierung). Ein vollständiges Beispiel gibts am Ende.

    Netzschleicher schrieb:

    Und die nächste wäre, ob man dort dann auch gleich mit 'GetProgAdress' sämtliche
    von der jeweiligen DLL exportierten Funktionen holen und auch global verfügbar machen soll, oder dies dann doch erst in der Funktion in welcher diese benötigt werden.

    Das Beste ist es, wenn du möglichst ohne DLL-Exporte und möglichst mit Interfaces arbeitest; das spart dir viele Umstände. Beispiel ebenfalls am Ende.

    Netzschleicher schrieb:

    Die letzte wäre dann, alle DLLs-Handles sollten ja wenn diese nicht mehr gebraucht werden mit 'FreeLibrary()' wieder freigegeben werden. Im Falle des Ladens der DLLs ganz zu Begin würde ich diese dann im 'OnClose'-Event des Fensters wieder freigeben.

    Analog eben direkt nach Application->Run(); in der WinMain()-Funktion.

    Netzschleicher schrieb:

    Oder wäre das in dem Fall nicht nötig, da beim Beenden des Hauptfensters und somit des gesamten Programms sowieso alle Handels gelöscht werden?

    Dem ist zwar so, aber sauber ist das trotzdem nicht 😉 Zu einer initialize()-Routine gehört auch eine finalize()-Routine, die die DLLs wieder entlädt, und mit denen ein zukünftig denkbarer Benutzer deine DLLs auch schon vor dem Programmende wieder entladen kann.

    Wichtig ist übrigens noch: alle Module in deinem Projekt müssen mit dynamischer RTL und mit Laufzeitpackages (mindestens rtl*.bpl) gelinkt werden.

    ----------

    Nun ein zwecks Anschauung stark modifiziertes Beispiel aus einer DLL von mir (für den Export in ein Excel-Worksheet). Meine ad-hoc-Veränderungen habe ich nicht getestet, also keine Garantie, daß es auf Anhieb läuft.

    Zunächst die Headerdatei der DLL:

    // MExcelIntf.hpp
    #ifndef _MEXCELINTF_HPP
    #define _MEXCELINTF_HPP
    
    #include <System.hpp>
    
      // Die folgenden Präprozessorkonstanten, die man in den Projektoptionen definieren
      // kann, beeinflussen die Kompilierung der DLL:
      //
      //   MEXCELLIB_EXPORT - nur im DLL-Projekt definiert
      //   MEXCELLIB_IMPORT - wenn definiert, wird die DLL statisch gelinkt;
      //                     wenn nicht definiert, werden DLL und Routine zur Laufzeit geladen.
    #if defined(MEXCELLIB_EXPORT)
     #define MEXCELLIB_DLLFUNC __declspec (dllexport)
    #elif defined(MEXCELLIB_IMPORT) // statischer Import der DLL
     #define MEXCELLIB_DLLFUNC __declspec (dllimport)
    #else
     #define MEXCELLIB_DLLFUNC
     #define MEXCELLIB_DYNAMIC
    #endif
    
    namespace mexcel
    {
    
    ...
    
        // Irgendein Interface, das in der DLL eine Klasse implementiert
    class __declspec (uuid ("{3b474dec-9267-4b82-bd46-81ce10007f8b}"))
        ISheet : public IUnknown
    {
    public:
        virtual _di_ISheetCell getCell (int row, int col) = 0;
        virtual void saveToExcelFile (const String& fileName) = 0;
    };
    typedef System::DelphiInterface<ISheet> _di_ISheet;
    
        // Das "Library-Interface": ein Factory-Interface für Objekte, die
        // in der DLL implementiert werden.
    class __declspec (uuid ("{9ecc276c-76a5-494b-a5d3-8959469fa5a3}"))
        IExcelLib : public IUnknown
    {
    public:
        virtual int getVersion (void) = 0;
        virtual _di_ISheet createSheet (void) = 0;
        ...
    };
    typedef System::DelphiInterface<IExcelLib> _di_IExcelLib;
    
    static const int MExcelLibVersion = 2; // check for this version at startup. It always gets incremented
                                          // when a breaking interface change occurs.
    
    #ifdef MEXCELLIB_DYNAMIC
     void initialize (void);
     void finalize (void);
     _di_IExcelLib __stdcall GetLibraryIntf (void);
    #else // MEXCELLIB_DYNAMIC
     void initialize (void) {}
     void finalize (void) {}
     extern "C" MEXCELLIB_DLLFUNC _di_IExcelLib __stdcall GetLibraryIntf (void);
    #endif // MEXCELLIB_DYNAMIC
    
        // Diese Funktion vergleicht Version von Header und DLL. Sie muß natürlich
        // im Header implementiert sein, damit das funktioniert!
    void checkVersion (void)
    {
        if (GetLibraryIntf ()->getVersion () != MExcelLibVersion)
            throw Exception ("MExcelLibE.dll ist inkompatibel: die Anwendung erfordert Version %d, "
                             "aber die DLL hat die Version %d",
                ARRAYOFCONST ((MExcelLibVersion, GetLibraryIntf ()->getVersion ())));
    } // namespace mexcel
    
    #endif // _MEXCELINTF_HPP
    

    Die folgende Datei kümmert sich um das Laden der DLL:

    // MExcelIntf_Dynamic.cpp
    #include <vcl.h>
    #pragma hdrstop
    
    #include "MExcelIntf.hpp"
    
    namespace mexcel
    {
    
    #ifdef MEXCELLIB_DYNAMIC
    
    typedef _di_IExcelLib __stdcall (*GetLibraryIntfT) (void);
    
    static HMODULE hMExcelLib = 0;
    static GetLibraryIntfT GetLibraryIntf_Dynamic;
    
    void initialize (void)
    {
        hMExcelLib = LoadLibrary (TEXT ("MExcelLibE.dll"));
        if (!hMExcelLib)
        {
                // Fehlercode sofort abfragen; könnte von späteren Aufrufen wieder verändert werden
            DWORD lastError = GetLastError ();
    
            throw Exception ("Datei MExcelLibE.dll kann nicht geladen werden: %s",
                ARRAYOFCONST ((SysErrorMessage (lastError))));
        }
        GetLibraryIntf_Dynamic = GetProcAddress (hMExcelLib, "GetLibraryIntf");
        if (!GetLibraryIntf_Dynamic)
        {
                // erst wieder aufräumen
            FreeLibrary (hMExcelLib);
            hMExcelLib = 0;
            throw Exception ("Datei MExcelLibE.dll kann nicht geladen werden: 
                             "der Export \"GetLibraryIntf()\" wurde nicht gefunden");
        }
    }
    
    void finalize (void)
    {
        if (hMExcelLib)
        {
             FreeLibrary (hMExcelLib);
             hMExcelLib = 0;
             GetLibraryIntf_Dynamic = 0;
        }
    }
    
    _di_IExcelLib __stdcall GetLibraryIntf (void)
    {
        if (!hMExcelLib)
            initialize ();
        return GetLibraryIntf_Dynamic ();
    }
    
    #endif // MEXCELLIB_DYNAMIC
    
    } // namespace mexcel
    

    Die Verwendung in deinem Programm könnte so aussehen:

    // MyProject.cpp
    #include <vcl.h>
    #pragma hdrstop
    #include <tchar.h>
    
    #include "MExcelIntf.hpp"
    
    //---------------------------------------------------------------------------
    USEFORM("MainUnit.cpp", FrmMain);
    ...
    //---------------------------------------------------------------------------
    WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
    {
        try
        {
             mexcel::initialize ();
             mexcel::checkVersion ();
    
             Application->Initialize();
             Application->DefaultFont = Screen->MessageFont;
             ...
             Application->Run();
    
             mexcel::finalize ();
    

    Wie dir beim Lesen sicher aufgefallen ist, kannst du auch auf das Laden der DLL zum Programmstart verzichten. Wenn du mexcel::GetLibraryIntf() aufrufst und die DLL noch nicht geladen wurde, wird sie eben nachgeladen - also erst bei Bedarf, lazy loading. Allerdings will ich darauf hinweisen, daß dieser Mechanismus nicht threadsicher ist; wenn du aus einem Hintergrundthread auf mexcel::GetLibraryIntf() zugreifen können willst, mußt du die Funktion noch etwas ausbauen.



  • Hallo

    Netzschleicher schrieb:

    Allerdings hätte ich jetzt doch noch ein paar weitere Fragen. Oder sollte ich den Tread jetzt hier beenden und einen neuen Aufmachen bezüglich des DLL Handlings?

    Passt noch hierein.

    Netzschleicher schrieb:

    Die Fragen wären, wo normalerweise die DLLs geladen werden. Im Augenblick mache ich das im 'OnCreate'-Event des Hauptfensters. Allerdings habe ich auch schon gelesen das in den neueren C++Buildern für vorbereitende Schritte der Kontruktor des Fensters verwendet werden sollte. Gilt dies auch für das Laden von DLLs?

    Egal für was, nimm statt OnCreate immer den Konstruktor (und für OnDestroy immer den Destruktor)

    Netzschleicher schrieb:

    Und die nächste wäre, ob man dort dann auch gleich mit 'GetProgAdress' sämtliche
    von der jeweiligen DLL exportierten Funktionen holen und auch global verfügbar machen soll, oder dies dann doch erst in der Funktion in welcher diese benötigt werden.

    Halte ich für sinnvoll, wenn du anstatt globalen Funktionszeigern gleich Member-Variablen des Forms verwendest.

    Netzschleicher schrieb:

    Die letzte wäre dann, alle DLLs-Handles sollten ja wenn diese nicht mehr gebraucht werden mit 'FreeLibrary()' wieder freigegeben werden. Im Falle des Ladens der DLLs ganz zu Begin würde ich diese dann im 'OnClose'-Event des Fensters wieder freigeben. Oder wäre das in dem Fall nicht nötig, da beim Beenden des Hauptfensters und somit des gesamten Programms sowieso alle Handels gelöscht werden?

    Schon aus Gründen der Sauberkeit und der Gewöhnung solltest du immer ohne Ausnahme Speicherlecks schließen und dich nicht auf das Programmende verlassen. Verwende dafür den Destruktor des Forms.

    bis bald
    akari



  • so jetzt habt ihr mir gut was zu lesen gegeben. Aber das wird heute Abend nicht mehr ganz stattfinden. Die nächsten Tage aber sicher. 🙂

    Ich habe das Laden der DLLs jetzt in den Kontruktor des Forms verschoben. Dort wird auch der Splashscreen erzeugt und die geladenen Module (Dlls) werden in einem Memo angezeigt. Das ich mir angewöhne meine reservierten Speicher und Zeiger ordentlich zu löschen habe ich auf jeden Fall vor nicht zu vernachlässigen. Wird auch in eigentlich allen Büchern mehrfach daraufhingewiesen.

    @akari
    Danke für den Tipp mit den Member-Variablen. Werd ich die Tage mich dranmachen.

    @audacia
    Danke für das Beispiel. Beim Überfliegen hab ich mir schon das eine oder andere herausgelesen.
    Werde das aber auf jeden Fall die nächsten Tage genauer Studieren.

    Ich habe mein Projekt mal soweit wie es eben jetzt schon ist als Release kompiliert und auf das
    Linken von Packages und der RTL verzichtet. In einer WinXP-VM lief die Anwendung dann nachdem ich
    noch nachträglich die 'rtl100.bpl' in das Programmverzeichnis kopiert habe. Wollte eben nicht ganz so viele zusätzliche DLLs und Packages mitverschiffen müssen.

    So, danke euch beiden schonmal. Jetzt ist zeit fürs Bett. Morgen möchte mein Hauptamtlicher Brötchengeber wieder Leistung von mir sehen. 🙂

    Grüße Netzschleicher



  • Netzschleicher schrieb:

    Ich habe mein Projekt mal soweit wie es eben jetzt schon ist als Release kompiliert und auf das Linken von Packages und der RTL verzichtet.

    Wir hatten das erst kürzlich; es mag auf den ersten Blick auch mit statischer Bindung an dynamische RTL und Packages funktionieren, aber richtig ist es nicht, und es kann dir die lustigsten Probleme bereiten.

    Im Minimalfall sind die einzigen DLLs/Packages, die du ausliefern mußt, sind cc32*mt.dll, borlndmm.dll, rtl*.bpl. Alle Packages, die sowohl von deiner Executable als auch von einer deiner DLLs referenziert werden, müssen zusätzlich als Laufzeitpackages eingebunden werden.



  • @audacia
    Hallo noch in Kürze für heute. Wurde spät in der Arbeit.

    Ich hab über Deine letzte Nachricht bezüglich der linkens der RTL und der Packages mal nachgedacht. Wenn ich das richtig verstanden habe, das braucht es zwingend die dynamisch gelinkte RTL und die Packages für das reibunglose Zusammenspiel zwischen einer Hauptanwendung und der dazu gehörenden DLLs. Vorausgesetzt natürlich das ich das ganze ordentlich Programmiert habe.
    Und das es in meinem genannten Beispiel mehr oder weniger Zufall ist, das es so in einer VM läuft. Was sich dann aber beim weiteren Entwickeln der Anwendung und/oder auf einem anderen Zielsystem wieder ändern kann.

    Das heißt dann, das ich wenn ich mit statisch gelinkter RTL und Packages arbeiten möchte, eben alles in eine .EXE-Datei packen muß und nicht in DLL-Module aufgliedern kann, so wie ich es jetzt vorhabe.

    Hoffe auf morgen, das ich wieder mehr Zeit hab mich da hineinzudenken. 🙂



  • Netzschleicher schrieb:

    Ich hab über Deine letzte Nachricht bezüglich der linkens der RTL und der Packages mal nachgedacht. Wenn ich das richtig verstanden habe, das braucht es zwingend die dynamisch gelinkte RTL und die Packages für das reibunglose Zusammenspiel zwischen einer Hauptanwendung und der dazu gehörenden DLLs. Vorausgesetzt natürlich das ich das ganze ordentlich Programmiert habe.
    Und das es in meinem genannten Beispiel mehr oder weniger Zufall ist, das es so in einer VM läuft. Was sich dann aber beim weiteren Entwickeln der Anwendung und/oder auf einem anderen Zielsystem wieder ändern kann.

    Das heißt dann, das ich wenn ich mit statisch gelinkter RTL und Packages arbeiten möchte, eben alles in eine .EXE-Datei packen muß und nicht in DLL-Module aufgliedern kann, so wie ich es jetzt vorhabe.

    Grob gesagt: ja.

    Etwas detaillierter:

    Deine Anwendung "funktioniert zufällig", aber das ist nicht so sehr etwas, was nur bis zum nächsten Programmstart gilt, sondern eher davon abhängt, was du in deinem Programm machst. Irgendeine zukünftige, an sich völlig belanglose Änderung von dir kann unter dieser Fehlkonfiguration subtile bis fatale Folgen haben, die fast unmöglich zu diagnostizieren sind, wenn man sich mit dem Unterbau nicht auskennt.

    Allgemein gilt für DLLs:

    - Solange die DLL nur ein C- oder COM-Interface hat, brauchst du keine gemeinsamen Laufzeitbibliotheken verwenden. Das setzt allerdings voraus, daß du keine C++-Objekte irgendeiner Art (std::string, std::vector<>, selbstdefinierte Klassen, ...) zwischen DLL und Anwendung austauschst; genausowenig darfst du Delphi-/C++Builder-Konstrukte (String, DynamicArray<>, Variant, DelphiInterface<>, TObject-Subklassen wie Formulare, ...) hin- und herreichen. Auch darf keine der Funktionen, die deine DLL exportiert, eine Exception werfen. Dafür kannst du dann nach Belieben unterschiedliche Compiler für deine beiden Module verwenden.

    - Willst du C++-Objekte (s.o.) austauschen und C++-Exceptions (d.h. alles außer Exceptions, die von der Delphi-Exception-Klasse aus SysUtils.hpp abgeleitet sind) werfen können, so mußt du beide Module mit demselben Compiler übersetzen und mit der dynamischen C++-RTL (cc32*mt.dll) linken.

    - Willst du darüberhinaus Delphi/C++Builder-Konstrukte austauschen und Delphi-Exceptions werfen können, so mußt du zusätzlich die Anwendung als auch die DLL mit Laufzeitpackages linken, und zwar mit allen Laufzeitpackages, die sowohl von der Anwendung als auch von der DLL verwendet werden. Das ist mindestens rtl*.bpl; wenn die DLL beispielsweise nicht auf VCL-Code zugreift, kannst du vcl.lib trotzdem statisch linken und mußt nur rtl*.bpl weitergeben.



  • Vielen Dank für Deine präzise Ausführung. Ich werde die Projektoptionen entsprechend setzen. Es bringt mir ja schließlich nichts wenn ich dann irgendwann demnächst mit fortschreitender komplexität meiner Anwendung an Fehlern hängen bleibe die durch derart falsche Projekteinstellungen hervorgerufen werden.

    Ich habe zwar einiges an C / C++ Literatur Zuhause, aber alles nur "allgemein" ohne speziellen Bezug auf Windows bzw. den C++ Builder 2007. Aber vielleicht hätte
    ich auch mal im "Petzold" nachschlagen sollen. Den hab ich nähmlich. Dort steht ja auch einiges über DLLs drin.

    Zu guter letzt werde ich mir noch noch das C++ Builder Buch von Richard Kaiser zulegen. Das hab ich mir schon ne weile so mal vorgenommen. Ich denke da stehen auch noch sehr viele wissenwerte Details drin.

    Nochmals Danke das Du Dir die Zeit genommen hast, auch mit dem Beispiel der DLL Programmierung.

    Grüße Netzschleicher


Log in to reply