Zeiger auf Dialog löschen



  • So Urlaub vorbei. Habe das ganze nun getestet. Es funktioniert allerdings nur teilweise. Ich rufe SendMessage für 4 Dialoge auf. Bei 2en kommt die Nachricht aber nur an. Gibt es dafür eine Erklärung.



  • Hm merkwürdig, wenn es bei 2 Dialogen funktioniert. - Hast du denn nähere Informationen dazu?



  • Ich rufe hintereinander Sendmessage auf für alle 4 Dialoge

    SendMessage(m_pmydlg1->m_hWnd,WM_APPWICI,NULL,NULL);
    SendMessage(m_pmydlg2->m_hWnd,WM_APPWICI,NULL,NULL);
    SendMessage(m_pmydlg3->m_hWnd,WM_APPWICI,NULL,NULL);
    SendMessage(m_pmydlg4->m_hWnd,WM_APPWICI,NULL,NULL);
    

    folgendes in jeder MessageMap der jeweiligen Klassen

    ON_MESSAGE(WM_APPWICI,&CMyDlg1::MyDestroyWindow)
    

    Funktion sieht dann wie folgt aus

    LRESULT CRuntimeInfoDlg::MyDestroyWindow(WPARAM wparam, LPARAM lparam)
    {
    	DestroyWindow();
    
    	delete this;
    
    	return (LRESULT)0;
    }
    

    Und noch was wenn DestroyWindow vom ersten Dialog aufgerufen wird. Wird DestroyWindow auch in allen weiteren Dialogen ausgeführt. Also vor SendMessage des jeweiligen Dialoges.



  • Also jetzt habe ich nochmals einen Test gemacht. Habe eine Extra DLL geschrieben die nur 3 Dialoge enthält. Und eine exe die die DLL verwendet. Und es stellt sich genau selbiges Verhalten ein.

    Wenn ich folgendes aufrufe:

    #define WM_APPDLG WM_APP + 1
    SendMessage(m_myDialog1->m_hWnd,WM_APPDLG,NULL,NULL);
    

    Wird die Nachricht vom Dialog 1 abgefangen was ja auch richtig ist. Nach dem aufruf von DestroyWindow(); wird dann allerdings von jeder Dialogklasse PostNcDestroy(); aufgerufen. Die Nachrichten die dann an die anderen Dialoge gesendet werden ja dann nicht mehr abgefangen. Da die Dialoge zu dem Zetpunkt dann zerstört sind. Wieso werden denn die anderen Dialoge auch gleich zerstört.

    Wie ist denn die richtige Vorgehensweise.


  • Mod

    Wenn das Kind Dialoge des ersten Dialoges sind, ist dieses Verhalten doch logisch oder?



  • Wenn das Kind Dialoge des ersten Dialoges sind, ist dieses Verhalten doch logisch oder?

    Ja wenn es Kind Dialoge wären. Sind es aber nicht. Sind alles eigenständige Dialoge.



  • Wurden wie folgt angelegt in InitInstance() angelegt:

    m_myDialog1 = new CMyDialog1;
    m_myDialog1->Create(IDD_DIALOG_MYDIALOG1);
    
    m_myDialog2 = new CMyDialog2;
    m_myDialog2->Create(IDD_DIALOG_MYDIALOG2);
    
    m_myDialog3 = new CMyDialog3;
    m_myDialog3->Create(IDD_DIALOG_MYDIALOG3);
    

    Nun ist doch von keinem das andere Kind oder etwa doch?



  • Kann mir denn keiner helfen. Ist doch nun kein aussergewöhnliches Verhalten oder doch?


  • Mod

    Du hast einen Debugger.
    Setz einen Breakpoint PostNcDestroy!
    Schau Dir den Callstack an und dann kannst Du genau sehen wer Deine Objekte zerstört!

    Ansonsten: Minisample bauen und zum Testen zur Verfügung stellen.



  • Mit Callstack meinst du die Aufrufliste. (Armes Deutschland)

    Ok und darin sehe ich dass PostNCDestroy von der Funktion CWnd::OnNcDestroy() aus wincore.cpp aufgerufen wird und diese wiederum von CWnd::OnWndMsg(...) und nun. Das sagt mir leider immer noch nichts.

    Wie kann ich den mein mini beispiel hochladen. Muss ich mich registrieren?


  • Mod

    Zeigt der Callstack nicht mehr?
    Komisch. Vermutlich lädst Du nicht alle Debug Infos für die Systemdateien.
    Lade es irgendwohin und gib mir den Link!



  • Ok. Konnte jetzt erst antworten da ich in meiner Firma nicht uploaden darf.
    Also hier der Link. Projekt für Visual Studio 2008.

    http://www.file-upload.net/download-2146695/Dialogtest.zip.html


  • Mod

    Das ist doch Unfug was Du machst. Wenn Dein Prozess terminiert, dann muss Dir doch klar sein, dass alle Fenster aufgeräumt werden. Und das macht Windows bevor die DLLs alle entladen werden.

    Das zeigt auch der Stacktrace:

    >	DialogDll.dll!CDialogDllApp::ExitInstance()  Line 76	C++
     	DialogDll.dll!InternalDllMain(HINSTANCE__ * hInstance=0x665d0000, unsigned long dwReason=0, void * __formal=0x00000001)  Line 155	C++
     	DialogDll.dll!DllMain(HINSTANCE__ * hInstance=0x665d0000, unsigned long dwReason=0, void * lpReserved=0x00000001)  Line 272	C++
     	DialogDll.dll!__DllMainCRTStartup(void * hDllHandle=0x665d0000, unsigned long dwReason=0, void * lpreserved=0x00000001)  Line 546 + 0x11 bytes	C
     	DialogDll.dll!_DllMainCRTStartup(void * hDllHandle=0x665d0000, unsigned long dwReason=0, void * lpreserved=0x00000001)  Line 510 + 0x11 bytes	C
     	ntdll.dll!_LdrpCallInitRoutine@16()  + 0x14 bytes	
     	ntdll.dll!_LdrShutdownProcess@0()  - 0x96 bytes	
     	ntdll.dll!_RtlExitUserProcess@4()  + 0x74 bytes	
     	kernel32.dll!75952ae4() 	
     	msvcr90d.dll!__crtExitProcess(int status=0)  Line 732	C
     	msvcr90d.dll!doexit(int code=0, int quick=0, int retcaller=0)  Line 644 + 0x9 bytes	C
     	msvcr90d.dll!exit(int code=0)  Line 412 + 0xd bytes	C
     	Dialogtest.exe!__tmainCRTStartup()  Line 599	C
     	Dialogtest.exe!WinMainCRTStartup()  Line 403	C
     	kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes	
     	ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes	
     	ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes
    


  • Das ist doch Unfug was Du machst.

    Ok, danke für deine klare Aussage. Ja soory Profi in MFC darf ich mich leider noch nicht nennen.
    Welche Zeile sagt mir das genau im Stacktrace 😕

    Aber was eigentlich noch viel wichtiger ist. Wie löse ich das Problem nun?


  • Mod

    Du kannst hier dirrekt auf den CRT Sartup Code springen und sieht dort, dass hier das Programm beendet wird.

    msvcr90d.dll!exit(int code=0)  Line 412 + 0xd bytes    C 
    Dialogtest.exe!__tmainCRTStartup()  Line 599    C
    

    Dein Fehler ist es, dass Du aufräumst, wenn die DLL entladen wird.
    Da das entladen zudem noch aus jedem beliebigen Thread erfolgen kann, vergrößert das Problem noch.

    Bau eine explizite Funktion für die DLL die aufräumt (Code hast Du ja schon in ExitInstance). Diese musst Du dann aus der EXE aufrufen.

    ExitInstance und InitInstance in einer DLL werden direkt aus DllMain aufgerufen. Daduch gibt es alle relevanten Einschränkungen die eben auch für DllMain gelten.



  • Also erst mal danke für deine Hilfe.

    Bau eine explizite Funktion für die DLL die aufräumt (Code hast Du ja schon in ExitInstance). Diese musst Du dann aus der EXE aufrufen.

    Genau hier liegt noch ein Problem. Und zwar wird diese DLL nicht von einer exe verwendet sondern von einem anderen System. System nennt sich WinCC von Siemens. Ein Tool für die Visualisierung in der Automatisierung. Wenn nun die erstellte Benutzeroberfläche z.B. über einen Button beendet wird kann sehr wohl eine Funktion aufgerufen werden um die DLL zu entladen. Allerdings wenn das System über den Stop Button des Entwicklungs- und Startexplorer heruntergefahren wird, ist es nicht mehr möglich eine Funktion auszuführen. Das System wird einfach beendet und die DLL entladen.



  • Also jetzt habe ich die Funktionalität mal in eine Exportfunktion der DLL gepackt:

    extern "C" __declspec(dllexport) void DeleteDialogs()
    {
    	SendMessage(theApp.m_myDialog1->m_hWnd,WM_APPDLG,NULL,NULL);
    	SendMessage(theApp.m_myDialog2->m_hWnd,WM_APPDLG,NULL,NULL);
    	SendMessage(theApp.m_myDialog3->m_hWnd,WM_APPDLG,NULL,NULL);
    }
    

    und die Funktion von ExitInstance aus meinem Testprogramm aufgerufen.

    int CDialogtestApp::ExitInstance()
    {
    	DeleteDialogs();
    
    	return CWinAppEx::ExitInstance();
    }
    

    Dann tritt genau das selbe Problem auf.



  • Man. So ein Mist. Wie bekomme ich den das Problem gelöst? Hilffeee!



  • Vieleicht hat ja irgenwann ja doch wieder Lust mir zu antworten. Wieso darf ich in ExitInstance der DLL einen Dialog so beenden:

    m_myDialog->DestroyWindow();
    delete m_myDialog;
    

    Dort sollte ich doch dann genau das selbe Problem haben. Wenn nicht, wieso?


Anmelden zum Antworten