[EDIT]
könnte den Beitrag bitte ein Moderator in die PC-Programmierung
verschieben, ist definitiv das falsche Forum.
Danke
[/EDIT]
Hallo zusammen,
folgende Ausganssituation:
Ich habe eine DLL, die mit einer CAN-Karte kommunizieren soll (dafür
gibt es vom Hersteller der Karte eine DLL). Meine DLL hat zunächst nur
einen Dialog.
Jetzt braucht die CAN-DLL (um mir mitteilen zu können, dass eine
CAN-Nachricht von der Karte empfangen wurde) ein Fenster-Handle. Um den
CAN-Empfang jedoch von meinem Dialog unabhängig zu halten, wollte ich
einen zweiten (unsichtbaren) Dialog erstellen, mit dessen MessageQueue
ich die Nachrichten von der CAN-DLL empfangen und entsprechend
verarbeiten kann.
Soweit kein großes Problem.
Der Code des zweiten Dialogs (CCanMessageReceiver) ist bislang recht
übersichtlich:
Das Problem an der Sache ist, dass ich bei dem Aufruf von DestroyWindow
im Destruktor eine Assertion in der wincore.cpp Zeile 398 bekomme. Wenn
ich den expliziten Aufruf raus nehme bekomme ich eine TRACE-Nachricht,
dass die Funktion implizit gerufen wird und es kommt die gleiche
Assertion.
Wenn ich das richtig verstanden habe ist die Zeile 398 Bestandteil der
Funktion, die für das Verteilen von Nachrichten zuständig ist (Code s.
unten). Es schaut also so aus, als ob jemand meinem nicht mehr
vorhandenen Dialog versucht eine Nachricht zu schicken... Nur wer?
Hier der Code der Funktion, in der die Assertion ausgelöst wird:
Ich habe auch schon versucht dem Dialog vor dem Destuktoraufruf eine
WM_CLOSE-Nachricht zu schicken, aber die kommt nie an (zumindest wird
der Breakpoint in der OnClose-Funktion nie angesprungen.
Kann mir jemand weiter helfen, wie ich die Assertion beseitige?
Vielen Dank vorab fürs lesen und viele Grüße
Hmm.
Das ist offenbar ein nicht modaler Dialog.
Kannst du ein vollständiges Minimalbeispiel zusammenstellen und Zippen?
IMHO.
DestroyWindow kommt nicht in den Destruktor, sondern zb in die OnCancel
Funktion.
Dafür fehlt mir die PostNCDestroy Funktion, die eigentlich nur delete
this machen machen muss
Für nicht modale Dialoge gibt es einige Artikel im Web, die einem
zeigen, wie sie zu machen sind. Damit sollte es eigentlich keine
Probleme geben. Bei MFC Fragen ist auch heute noch CodeProject immer ein
guter Anlaufpunkt.
http://www.codeproject.com/KB/dialog/gettingmodeless.aspx
Hallo Karl-Heinz,
danke für die Antwort und den Link zu dem Artikel.
Leider gestaltet sich das mit dem Minimalbeispiel etwas schwierig und
der Artikel beschreibt auch nicht unbedingt mein Szenario...
Deswegen versuche ich das Ganze mal etwas ausführlicher zu beschreiben.
Meine DLL soll eine Simulation in der KEIL Entwicklungsumgebung werden.
Dafür muss meine DLL eine Funktion exportieren, die von KEIL zu
bestimmten Zeitpunkten aufgerufen wird. Einer der Zeitpunkte ist, wenn
ich mein Hauptfenster anzeigen muss. In diesem Fall wird das
Hauptfenster erzeugt und eben angezeigt.
Gleichzeitig habe ich mehrere statische Objekte (die also angelegt
werden, sobald die DLL geladen wird). Eins davon ist mein unsichtbarer
Dialog.
Da die Konstruktion der statischen Objekte vor dem Aufruf von
CWinApp::InitInstance(); passiert habe ich das Create aus dem
Konstruktor des unsichbaren Dialogs herausgenommen und in eine extra
Funktion gepackt, die sicher erst gerufen wird, wenn KEIL meine DLL
geladen hat und CWinApp::InitInstance() gerufen wurde.
Wenn ich den Debugger von KEIL schließe wird auch meine DLL entladen -
und damit natürlich die statischen Objekte zerstört.
Wenn ich im Destruktor meines unsichtbaren Dialogs kein DestroyWindow()
stehen habe bekomme ich folgende TRACE-Nachricht in VisualStudio:
1
Warning: calling DestroyWindow in CDialog::~CDialog --
2
OnDestroy or PostNcDestroy in derived class will not be called.
3
Second Chance Assertion Failed: File f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp, Line 398
4
uv3.exe hat einen Haltepunkt ausgelöst.
Wenn ich den Aufruf drin habe ist die erste Warning weg, der Rest bleibt
bestehen.
Die Anmerkung mit dem PostNcDestroy (und dem darin befindlichen delete
this) bringt mich leider nicht weiter, weil ich den Dialog ja nie mit
new allokiere - und deswegen auch kein delete machen darf...
Ich hatte auch versucht meinem unsichtbaren Dialog vor der Destruktion
eine WM_CLOSE-Nachricht zu schicken, aber die kam wie gesagt nicht an
(auch wenn ich nicht verstehe, warum nicht...).
Wie gesagt, das Ganze als Minimalbeispiel zu gestalten ist schwierig,
weil Du dann auch den KEIL bräuchtest und dort wiederrum ein Projekt,
das dann die DLL lädt etc.
Ich hoffe dennoch, dass meine Ausführungen mein Problem verdeutlicht
haben und mir vielleicht doch geholfen werden kann.?
Viele Grüße
Michael Klose schrieb:
> Wie gesagt, das Ganze als Minimalbeispiel zu gestalten ist schwierig,> weil Du dann auch den KEIL bräuchtest und dort wiederrum ein Projekt,> das dann die DLL lädt etc.
Kopfkratz.
Ja, das ist in der Tat dann schwierig.
> Gleichzeitig habe ich mehrere statische Objekte (die also> angelegt werden, sobald die DLL geladen wird). Eins davon ist> mein unsichtbarer Dialog.> Da die Konstruktion der statischen Objekte vor dem Aufruf von> CWinApp::InitInstance();
Das muss ja nicht so sein.
Dein statisches "Objekt" kann ja auch ein Pointer auf den Dialog sein,
der dann erst in der InitInstance tatsächlich mittels new angelegt wird.
Auf die Art "verzögerst" du die Dialogerstellung ohne dass der Dialog
etwas davon wissen muss.
Mann könnte sogar weiter gehen und den Dialog erst dann erzeugen, wenn
er das erste mal gebraucht wird. Ein Singleton-Pattern also.
> Die Anmerkung mit dem PostNcDestroy (und dem darin befindlichen> delete this) bringt mich leider nicht weiter, weil ich den Dialog> ja nie mit new allokiere - und deswegen auch kein delete machen darf...
wmoit sich dieses Problem dann auch in Luft auflöst. Der Dialog wird
nach den klassischen Methoden für modeless Dialoge programmiert,
"getrickst" wird lediglich in der DLL-Umgebung. Der Dialog muss davon
gar nichts wissen.
Hi,
Karl heinz Buchegger schrieb:
> Das muss ja nicht so sein.> Dein statisches "Objekt" kann ja auch ein Pointer auf den Dialog sein,> der dann erst in der InitInstance tatsächlich mittels new angelegt wird.> Auf die Art "verzögerst" du die Dialogerstellung ohne dass der Dialog> etwas davon wissen muss.> Mann könnte sogar weiter gehen und den Dialog erst dann erzeugen, wenn> er das erste mal gebraucht wird. Ein Singleton-Pattern also.
So hatte ich das Anfangs auch. Da war dann der Create-Aufruf im
Konstruktor und der DestroyWindow-Aufruf im Destruktor. Aber das hat
eben genau das Problem verursacht, deswegen hatte ich gehofft, dass ich
es anders gelöst bekomme - was sich ja als Irrweg herausgestellt hat...
Deinen Antworten entnehme ich aber, dass ich zumindest mal keinen
konzeptionellen Bock geschossen habe, oder? So rein von den Überlegungen
her sollte das also funktionieren, oder?
Andere Frage: hast Du nen KEIL installiert (gibts als kostenlose Demo)?
Wenn ja würde ich am Wochenende doch mal versuchen, ob ich das Ganze als
Minimalbeispiel hinbekomme und würds am Montag hier reinstellen.
Ich verstehe halt nicht so recht, wer meinem Fenster eine Nachricht
schicken sollte, nachdem es nicht mehr da ist - und vor allem verstehe
ich ganz und gar nicht, warum es auch keine WM_CLOSE-Nachricht empfängt,
wenn ihm diese gesendet wird.
Viele Grüße
Hallo zusammen,
das Problem ist gelöst!
Es hatte einen ganz anderen Grund, als ich eigentlich gedacht hatte -
wie das immer so ist...
Falls jemand mal ein ähnliches Problem hat, hier noch meine Erklärung:
Das Problem war, dass die Funktion DestroyWindow() ZU SPÄT gerufen
wurde. Da das Objekt statisch angelegt wurde wurde es erst zerstört, als
die DLL schon entladen war (meine Vermutung). Zu diesem Zeitpunkt war
wohl schon ein Teil des Dialogs zerstört und dadurch kam die Assertion.
Ich habe jetzt herausgefunden, dass der KEIL-Simulator bekannt gibt,
wenn er beendet wird. Jetzt habe ich zu implementiert, dass der Dialog
zu diesem Zeitpunkt benachrichtigt wird und die DestroyWindow()-Funktion
ruft -> keine Assertion mehr.
Viele Grüße