DoModal in Threads



  • Hallo,

    ich habe eine DLL geschrieben und öffne dort einen MFC Dialog modal.
    Dieser Dialog besitzt einen Quit Knopf mit CDialog::OnOK() und einen Timer der nach 3 Minuten die Funktion des OnOK() Knopf aufruft und sich zuvor mit KillTimer natürlich deaktiviert.
    AFX State ist eingebaut.
    Gestartet wird der Dialog in einem Thread:

    dialogthread=AfxBeginThread(DialogThreadFunktion,NULL,THREAD_PRIORITY_NORMAL);
    

    Drücke ich den Quit Knopf wird der Thread verlassen nach dem DoModal.
    Ist der Timer fällig dann wird CDialog::OnOK() korrekt aufgerufen und auch verlassen, das DoModal im Thread wird aber nicht beendet und der Dialog hängt in irgendeinem Loop.

    Mache ich ein ExitInstance des Threads ist der Heap beleidigt.
    Drücke ich das X zum Schliessen beendet das DoModal richtig wie der Knopf.
    Mache ich ein PostMessage WM_CLOSE aus meinem Timer dann beendet DoModal nicht.
    Auch ein Syscommand SC_CLOSE funktioniert nicht.
    Alles was ich drücke funktioniert, alles was per Timer ausgelösst wird nicht.

    Was mache ich hier falsch?



  • Ich habe den Dialog nun auf nicht modal umgeschrieben und hänge nun beim DestroyWindow wenn der Dialog nach dem Create einmal mit SW_SHOW angezeigt wurde. Bleibt er auf SW_HIDE dann funktioniert DestroyWindow.
    Nachdem OnOK() ebenfalls DestroyWindow aufrufen wird bin ich wohl nicht weitergekommen.

    Lasse ich destroywindow weg und mache ein "delete modelessdialog" dann bleibt delete hängen.


  • Mod

    Sendest Du irgendwas an einen anderen Thread, der auf was wartet?
    Was sagt die Codeposition wenn Du einen Break-All machst. Wo steht der Thread?



  • Kein Sendmessage, kein Postmessage.
    Ich öffne dort den Seriellen Port und sende was. Vor dem Beenden wird alles schön geschlossen.
    Der Code hängt im Loop in der ntdll.dll.



  • Ich habe jetzt einen neuen Dialog gebastelt.
    Es handelt sich um einen Standard neuen Dialog in MFC ohne sonstwas.
    Der Dialog wird in diesem Thread in einer DLL aufgerufen:

    UINT DialogThreadFunktion(LPVOID param)
    {
    	//Open a modeless dialog
    	AFX_MANAGE_STATE(AfxGetStaticModuleState());
    	CTestDialog dialog=new CTestDialog();
    	dialog->Create(CTestDialog::IDD);
    	settingdialogopened=true;
    	while(settingdialogopened==TRUE){dialog->ProcessMessages();Sleep(0);}
    	dialog->DestroyWindow();
    	delete dialog;
    	dialog = NULL;
    	settingdialogopened=true;
    	dialogthread=NULL;
    	return 0;
    }
    

    Das ist die Message Loop im CTestDialog:

    void CTestDialog::ProcessMessages(void)
    {
    	CWinApp* pApp = AfxGetApp();
    	MSG msg;
    	int count = 0;
    	while ( PeekMessage ( &msg, NULL, 0, 0, PM_NOREMOVE ))
    	{
    		pApp->PumpMessage();
    		count++;
    		if(count > 1){return;}
    	}
    }
    

    Beim Beenden der DLL wird settingdialogopened auf false gesetzt und der Dialog sollte destroyed und deleted werden was beim Destroy endet.
    Im DLL exit code warte ich solange bis settingsdialogopened wieder true wird.
    Wenn ich hingegen im Dialog das X Drücke funktioniert es tadellos.
    Ein Postmessage mit WM_CLOSE/SC_CLOSE hingegen bleibt hängen.
    Das ist jetzt wirklich zum Verzeifeln 😡



  • @thenoname
    Wieso verwendest du nen eigenen Message-Loop und nicht wirklich DoModal?

    Ansonsten...
    MFC GUI in einem eigenen Thread laufen lassen geht grundsätzlich problemlos. Warum es bei dir nicht hinhauen will weiss ich leider nicht.



  • Ich habe ja anfangs DoModal verwendet, bin nun aber auf der Spurensuche warum es nicht klappen will.
    Wie schon erwähnt, wenn man den Dialog per Maus bedient klappt alles tadellos nur wenn remote beendet wird ist es vorbei. Ich habe selber viele DLL's mit diesen Dialogen und es verhält sich überall identisch. Remote shutdown nicht möglich.



  • So, ich habe jetzt ein finales Ergebnis:
    Ein Postmessage WM_CLOSE bei einem Dialog der in einer DLL ausgeführt wird schliesst den Dialog.
    Ausnahme: Wenn diese Nachricht im Detach der DLL = CWinApp::ExitInstance() der CWinapp aufgerufen wird.
    Schliesst man also beim Beenden der DLL den in einem Thread mit DoModal ausgeführen Dialog dann gibt es einen Deadlock wie oben beschrieben.
    Schliesst man ihn vor dem DLL Detach dann klappt alles.
    Das liegt wohl daran, das das CWinApp Objekt nach dem Auflösen des Dialogs zerstört wird und die ExistInstance damit irgendwo ins Leere greift. Also ein Programmierfehler.



  • Ochjeh...

    ExitInstance einer DLL wird vom DLL_PROCESS_DETACH Handler ( DllMain ) aufgerufen.
    Da drinnen kannst du so-gut-wie überhaupt nix sinnvoll machen, weil gerade der Loader-Lock gehalten wird.

    Und darauf dass irgend ein Thread sich beendet kannst du auch nicht warten, eben wegen des Loader-Lock:

    Because DLL notifications are serialized, entry-point functions should not attempt to communicate with other threads or processes. Deadlocks may occur as a result.

    Und ohne auf das Beendes des Thread zu warten ein WM_CLOSE zu posten ist auch nicht wirklich OK, da ja dann der Thread noch laufen würde während die DLL die seinen Code enthält schon entladen wurde.


Anmelden zum Antworten