C++Builder XE2 TSearchRec
-
Hallo Forengemeinde,
aus gegebenen Gründen habe ich mir einen C++Builder XE2 zugelegt.
Beim migrieren meines Programmes bin ich dann auf folgendes Problem gestoßen.In einem Formular welches sich in einer dynamisch geladenen DLL befindet habe ich einen kleinen Version-Info-Dialog, welcher über FindFirst und FindNext alle zu dem Programm gehörenden Dateien einliest, die Versions-Info ausliest und in einem ListView anzeigt. Soweit so gut, das funktioniert alles. Jedoch erhalte ich beim Beenden des Programmes eine 'access Violation'. Und diese auch nur wenn ich wärend des Programmlaufs den Version-Info-Dialog geöffnet hatte.
Ich habe dann das Modul soweit abgespeckt und herausgefunden das es am 'TSearchRec' liegt.Das Problem lässt sich sehr einfach nachvollziegen. Einfach eine Form anlegen und auf dieser einen Button. Dazu eine DLL mit einem enthaltenen Formular. Mit dem Button auf der exe.Form die DLL dynamisch laden und die Funktion zum Anzeigen des DLL-Formulars aufrufen. Dann genügt ein einfaches 'TSearchRec TestSearch' im z.B. Kontruktor des DLL-Formulars um beim Beenden des exe.Forms die 'access violation' zu erzeugen. Beim statischen laden der DLL läuft es Fehlerfrei.
Beim Debugging habe ich den CodeGuard eingeschaltet.Header-Datei der DLLTest.exe
// --------------------------------------------------------------------------- #ifndef TestMainFormH #define TestMainFormH // --------------------------------------------------------------------------- #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Vcl.StdCtrls.hpp> #include <Vcl.Forms.hpp> // --------------------------------------------------------------------------- class TForm1: public TForm { __published: // Von der IDE verwaltete Komponenten TButton *Button1; void __fastcall Button1Click(TObject *Sender); private: // Anwender-Deklarationen public: // Anwender-Deklarationen __fastcall TForm1(TComponent* Owner); }; // --------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; // --------------------------------------------------------------------------- #endif
Source-Datei der DLLTest.exe
// --------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "TestMainForm.h" // --------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" //#pragma link "DLLModul.lib" TForm1 *Form1; //extern "C" __declspec(dllimport) void ShowForm(TComponent* Owner); // --------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner) { } // --------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { typedef void TShowForm(TComponent* Owner); TShowForm *ShowForm; HMODULE hDLL = LoadLibrary(L"DLLModul.dll"); if (hDLL) { try { ShowForm = (TShowForm*) GetProcAddress(hDLL, "_ShowForm"); if (ShowForm) ShowForm((TComponent*)Sender); } __finally { FreeLibrary(hDLL); ShowForm = NULL; } } } // ---------------------------------------------------------------------------
Header-Datei der DLLModul.dll
// --------------------------------------------------------------------------- #ifndef DLLForm1H #define DLLForm1H // --------------------------------------------------------------------------- #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Vcl.StdCtrls.hpp> #include <Vcl.Forms.hpp> // --------------------------------------------------------------------------- class TForm2: public TForm { __published: // Von der IDE verwaltete Komponenten private: // Anwender-Deklarationen public: // Anwender-Deklarationen __fastcall TForm2(TComponent* Owner); }; // --------------------------------------------------------------------------- extern PACKAGE TForm2 *Form2; // --------------------------------------------------------------------------- #endif
Source-Code der DLLModul.dll
// --------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "DLLForm1.h" // --------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm2 *Form2; // --------------------------------------------------------------------------- __fastcall TForm2::TForm2(TComponent* Owner): TForm(Owner) { TSearchRec TestRecord; Caption = "OK"; } // --------------------------------------------------------------------------- extern "C" __declspec(dllexport) void ShowForm(TComponent *Owner) { Form2 = new TForm2(Owner); Form2->ShowModal(); delete Form2; Form2 = NULL; }
Source-Datei der DLL selbst
// Important note about DLL memory management when your DLL uses the // static version of the RunTime Library: // // If your DLL exports any functions that pass String objects (or structs/ // classes containing nested Strings) as parameter or function results, // you will need to add the library MEMMGR.LIB to both the DLL project and // any other projects that use the DLL. You will also need to use MEMMGR.LIB // if any other projects which use the DLL will be performing new or delete // operations on any non-TObject-derived classes which are exported from the // DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling // EXE's to use the BORLNDMM.DLL as their memory manager. In these cases, // the file BORLNDMM.DLL should be deployed along with your DLL. // // To avoid using BORLNDMM.DLL, pass string information using "char *" or // ShortString parameters. // // If your DLL uses the dynamic version of the RTL, you do not need to // explicitly add MEMMGR.LIB as this will be done implicitly for you #include <vcl.h> #include <windows.h> #pragma hdrstop #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; }
Hat jemand eine Idee wie der Fehler umgangen werden kann oder woran das es liegt?
Vielen Dank Netzschleicher
-
Nachdem ich nun noch einige Zeit versucht habe den Fehler zu finden, habe ich den auf TSearchRec, FindFirst und FindNext basierenden Programmteil durch die Win32-API Funktionen FindFirstFile und FindNextFile ersetzt. Nun funktioniert es wie es soll, ohne 'access violation'.
Interessieren würde es mich aber dennoch wo der Fehler bei 'TSearchRec' liegt. Oder ist das einer der doch recht zahlreichen Bugs im C++Builder XE2?
Gute Nacht und Grüße Netzschleicher
-
Netzschleicher schrieb:
Interessieren würde es mich aber dennoch wo der Fehler bei 'TSearchRec' liegt.
Mich auch, leider habe ich aber keine Lizenz dafür und kann es nicht ausprobieren. Du kannst ja mal mit den Debug-Bibliotheken linken und dann in den VCL-Code steppen, um zu schauen, wo der Fehler herkommt. (Ich unterstelle jetzt mal, daß du bei Anwendung und DLL auf die richtige Laufzeitpackage-Konfiguration geachtet hast
)
-
Weiterhin würde ich bei ShowForm(TComponent *Owner) den Owner Parameter weglassen. Der Owner ist ja für das Löschen der Form zuständig. Erstens wird die Form in der dll selbst gelöscht und zweitens halte ich es für keine gute Idee das Löschen außerhalb der dll (von der Anwendung) vorzunehmen.
-
Kann den Fehler leider nicht nachvollziehen, klappt bei mir ohne Zugriffsverletzung.
Anbei Projekt mit erstellter EXE und DLL
http://www.magixsoft.de/DLLTest.zip
-
@audacia
Ich habe beide (die .exe Datei und die .dll) mit der RTL und den Laufzeitpackages gelinkt. So wie es ja auch sein sollte.@VergissEs
Ich habe mir das von Dir erstellte Projekt auf die Platte kopiert und im Builder XE2 geöffnet. In den Projektoptionen hattest Du denn CodeGuard deaktiviert. Diesen habe ich bei beiden Projekten eingeschaltet. Ein Debugrun ergab dann keinen Fehler. Erst als ich beide Projekte jeweils bereinigt und neu kompiliert habe, trat der Fehler wieder auf.
Sollte das etwas damit zu tun haben das ich parallel noch mein Rad Studio 2007 installiert habe? Oder spielt mir da doch etwas
mein Windows7 64Bit einen Streich?@Braunstein
Danke für den Tipp. Werd mich diesbezüglich genauer Belesen und das dann Ändern.
-
Mir ist gerade eingefallen das ich in einer Virtuellen Windows7 32Bit Maschine noch eine Installation meines Builders XE2 habe. Ohne irgendwelche Fremdkomponenten und ohne ein parallel installiertes RAD Studio 2007. Ich habe also das Testprojekt mal eben dort hineinkopiert und neu compiliert. Auch dort lässt sich der Fehler eindeutig nachvollziehen. Zumindest denke ich jetzt mal davon ausgehen zu können, das es weder an meiner 64Bit-Umgebung noch am parallel vorhandenen RAD Studio 2007 liegt.
-
Hab den Codeguard nun aktiviert die Projekte bereinigt und neu erstellt.
Immer noch keine nachvollziehbare Zugriffsverletzung.Evtl mal ein diff von deiner Projektdatei machen und von meiner?
-
@VergissEs
Ich habe nun Dein Projekt, so wie es bei mir den Fehler hervorbringt gezippt.
Das 'fehlerhafte Projekt' habe ich hier zum herunterladen eingestellt:[url]
http://www.file-upload.net/download-4269483/DLLTest_error.zip.html
[/url]
-
Sorry, habe immer noch nicht den Fehler, auch nach neukompilieren bzw wenn ich deine zugemailte EXE direkt ausführe klappt alles ohne Fehlermeldung.
PS:
Hab auch Windows 7 64 Bit am Start mit installierter Vorversion RADStudio 2009.
Habe erst XE2 seit Update #4 installiert.
-
Nun verstehe ich garnichts mehr.
Mache gerade in einer VM nochmals eine komplette Neuinstallation.
Mal sehen was da dann herauskommt.
-
Ich habe das ganze nochmals neu in einer Win7 32Bit VM installiert und das besagte Projekt geöffnet.
Solange ich den CodeGuard nicht aktiviere ist alles OK. Sobald ich jedoch den CodeGuard einschalte, die Projekte bereinige und anschließend neu erstelle, bekomme ich die Zugriffsverletzung beim Beenden des Programmes.Die Revision des C++Builders XE2 ist: 16.0.4429.46931
Updates: Delphi XE2 und C++ builder XE2 Update 4 sowie Help Update 4