MFC-Dialog bleibt beim Aufruf in den Tiefen der MFC stecken (Visual Studio 2005)



  • Hallo,

    in meiner Anwendung sind alle Dialoge von einer BaseDialog-Klasse abgeleitet,
    die die Haupteigenschaften aller Dialoge bestimmt. So ist dort z.B. OnCommand()
    sowie DoModal überschrieben. Ein Zweck davon ist es, die Eingabe Controls, wie
    Edit-Felder, etc. mit einer spezifischen Tastatur zu belegen, um sie über ein
    Touch-Panel bedienen zu können.

    Das funktioniert so schon sehr lange.

    Nun habe ich allerdings ein paar meiner Dialoge über ein TabCtrl zusammengefasst!
    Dabei habe ich das im Forum schon erwähnte "DynTabCtrl" verwendet.

    Allerdings ist der dazugehörige Haupt-Dialog, der das TabCtrl enthält, als einziger
    nicht von meinem BaseDialog abgeleitet.

    Nach einigen Schwierigkeiten wurden alle Dialoge in den Tabs angezeigt und verhalten
    sich zunächst normal. (Ich kann Tabs wechseln und OK und Cancel werden ausgeführt.)

    Nun aber der Fehler:
    Wenn ich in irgend einem Dialog, der sich unter den Tabs befindet, in ein Eingabe-
    Control reinklicke, bleibt die ganze Anwendung einfach hängen!

    Die genaue Stelle, an der es endgültig endet, ohne Fehlermeldung und sonstige
    Hinweise, ist in der "dlgcore.cpp", innerhalb der Methode:

    BOOL CWnd::CreateDlgIndirect(LPCDLGTEMPLATE lpDialogTemplate,
    	CWnd* pParentWnd, HINSTANCE hInst),
    

    an der Stelle:

    // create modeless dialog
    		AfxHookWindowCreate(this);
    		hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate,
    			pParentWnd->GetSafeHwnd(), AfxDlgProc);
    

    Beim Aufruf von "CreateDialogIndirect"

    Allerdings musste ich an den Properties der Tab-Dialoge etwas ändern.

    "Style" ist dort auf "Child" gesetzt. (damit er überhaupt als "Child" angezeigt wird)
    "Control" ist auf "TRUE" gesetzt. (damit er als "Child" besser arbeitet)

    Sobald ich "Control" wieder auf "FALSE" setze, funktioniert dieses "OnFocus"-Verhalten,
    nachdem die Tabs vollständig geladen wurden.
    Allerdings wird hier beim Ladevorgang ebenfalls ein "OnFocus"-Event ausgelöst, der
    mir die Tastatur-Dialoge für jeden Tab-Dialog läd, bevor der eigentliche Dialog auf dem
    Bildschirm erscheint.

    Ich befinde mich also in einem Dilemma!

    Kann mir bitte jemand helfen!

    Grüsse
    Helmut


  • Mod

    Verrate mir mal bitte warum, beim Klicken in ein Edit Control ein neuer Dialog angelegt wird.
    Denn das passiert hier offensichtlich.

    Der besagte Code in der MFC wird immer NUR dann ausgeführt, wenn ein neuer MFC Dialog erzeugt wird und hooked den Dialog über die zentrale MFC Window Proc.

    Also ist nicht die Frage, was in der MFC nicht funktioniert, sondern was in Deinem Dialog Template drin ist, dass CreateDialogIndirect zum blockieren bringt. Typisch ist da so etwas, wie das senden von Nachrichten an Fenster anderer Threads.

    Auch hier hilft Dir der Debugger: Break All Drücken und den Callstack ansehen.



  • Hallo Martin,

    vielen Dank für Deine Antwort.

    Und ja, es ist gewünscht, dass dieser OnFocus-Event ausgelöst und bearbeitet wird.
    Ich habe eine Anwendung für ein Touch-Panel und eine für den PC. Beide reagieren
    gleich und öffnen eine Touch-Tastatur durch den Klick in ein Edit-Feld!

    Hier, in der PC-Version wird eine Tastatur oder eine andere Eingabehilfe geöffnet.

    Alles das funktioniert auch sonst.
    Nun Habe ich allerdings über dieses "TabCtrl" zwangsweise noch einen Zwischen-Dialog
    eingefügt. Und der bringt das Verhalten durchcheinander.

    Da in der Anwendung einige Threads am Laufen sind, ist das mit dem "Break All"
    im Debugger nicht so eindeutig.

    Er bleibt dabei übrigens in "wincore.cpp" bei:

    /////////////////////////////////////////////////////////////////////////////
    // main WindowProc implementation
    
    LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
    	// OnWndMsg does most of the work, except for DefWindowProc call
    	LRESULT lResult = 0;
    	if (!OnWndMsg(message, wParam, lParam, &lResult))
    		lResult = DefWindowProc(message, wParam, lParam);
    	return lResult;
    }
    

    und zwar bei "DefWindowProc(message, wParam, lParam);" hängen.

    Direkt beeinflussen konnte ich das "OnFocus"-Verhalten durch Manipulation der
    Dialog-Property "Control".

    Aber wenn das eine Fehlverhalten eliminiert ist, tritt das Andere stattdessen ein.

    Grüsse
    Helmut


  • Mod

    Natürlich ist Break All Eindeutig.

    Du kannst exakt sehen, welcher Thread auf welchen anderen Thread wartet.
    Du kannst im Thread Fenster jeden Thread auswählen und den Callstack ansehen.

    Aber grundsätzlich: Vermeide SendMessage von mehreren Threads auf Deine UI. Außer Du weißt ganz genau was Du tust.

    Oder gehören die Fenster evtl. unterschiedlichen Threads an. Auch das ist zu vermeiden.



  • Alle Views und die darin aufgerufenen Dialoge sind Teil des Hauptprogramms.
    Es dürfte also kein Event von einem anderen Thread kommen.

    Meine Angaben sind leider nicht 100%-ig, da ich nicht den ganzen Code kenne.

    Die Dialoge selbst greifen nie auf einen anderen Thread und dessen Parameter zu.
    Dies sind alles nur Einstellungen, die in globalen Variablen und/oder der Registry
    gespeichert werden.

    Der betreffende Event ist auch eindeutg dem entsprechenden Dialogfeld zuzuordnen,
    egal ob er ohne ersichtlichen Grund kommt oder aktiv hervorgerufen zum Hänger führt.

    Die Threads sind nur durch Critical Sections untereinander synchronisiert.
    An dieser Stelle habe die eigentlich keinen Einfluss

    Nach dem Break habe ich allerdings noch keine Sicht auf einen bestimmten Thread geöffnet.
    Damit werde ich mich noch befassen.

    Grüsse
    Helmut



  • Leider hilft mir hier nichts weiter.
    Beim "Break All" im Debugger finde ich für mich nichts Verwertbares in den einzelnen Threads.

    Ich ändere eine Property, nämlich die "Control"-Property der Dialoge, die
    unter dem TabCtrl zusammengefasst sind auf "TRUE" und schon kippt das Verhalten
    von einem Fehler-Extrem ins andere.

    Rufe ich die Dialoge ohne TabCtrl auf, laufen sie fehlerfrei.

    TabCtrl und Control=FALSE:
    --> Es wird ein unerwünschter OnFocus-Event ausgelöst, der für jeden Tab
    den Tastatur-Dialog zum Edit-Feld aufruft, bevor der eigentliche Dialog
    angezeigt wird. Danach funktioniert alles wie gewünscht.
    Es hilft auch nicht, die Anweisungen auch der "OnInitDialog(..)" raus
    zu nehmen, damit keine Werte in die Edit-Felder geschrieben werden.

    TabCtrl und Control=TRUE:
    --> Der anfängliche OnFocus-Event bleibt aus. Es scheint sich alles normal zu
    verhalten. Doch mit Klick in eines der Edit-Felder hängt sich die ganze
    Anwendung auf (bleibt stehen). Den Grund finde ich auch nicht.

    Die Beschreibung dieser "Control"-Property lautet:
    "Creates a dialog that works well as a child of another dialog."

    Da ich die Dialoge für das TabCtrl als Child declarieren muss, erscheint mir
    das Setzen dieser Property sinnvoll. Ich habe auch schon ettliche Kombinationen
    mit und ohne dieser Property durchgespielt. Es kommt immer Müll raus!

    Der Debugger, auch mit Sicht auf die einzelnen Threads der Anwendung,
    hilft mir persönlich diesmal leider auch nicht weiter.

    Aber trotzdem vielen Dank für die Antworten.
    Hat sonst wirklich Keiner eine Idee?

    Grüsse
    Helmut


  • Mod

    Was nun?
    Ich denke Du hast einen Lock! Dann sagt Dir der Callstack der Threads auch was.
    Wenn es keinen Deadlock mit anderen Threads gibt, dann hast Du einen Deadlock, weil das System z.B. versucht ein Control zu finden dem es den Focus geben kan, aber keines findet.
    Und auch hier zeigt Dir der Callstack und die Symbole vermutlich was in der USER.DLL passiert.

    Was bitte ist ein unerwünschter OnFocus Event? Der Focus wird letzten Endes ja auch durch Dich gesetzt denn OnInitDialog gibt TRUE zurück, oder eben FALSE, wenn Du es machst?

    Jetzt schreibst Du, dass was nicht geht? Was nun?

    Ist Dir klar welcher Stil dass ist, den Du setzt?
    Vermutlich nicht... entsprechend hast Du auch nicht gelesen was das bedeutet?
    Es geht um vermutlich um WS_EX_CONTROLPARENT. Dieser Stil sorgt dafür, dass Dialoge geschachtelt werden können.



  • Du hast recht Martin.

    Mit der Theorie, die hier in der MFC steckt, bin ich nicht sehr vertraut.
    Darum sagen mir die Debug Ausgaben auch nicht so viel.

    Vielleicht brauch ich auch noch irgend eine Lektüre, die mir das erklärt.

    Einen Dead-Lock, weil ein Control nicht gefunden wird, kann ich mir am
    ehesten vorstellen.

    Das Auslösen eines OnFocus Events, nur weil der Dialog nun in einem TabCtrl sitzt,
    kann ich mir nicht (noch) vorstellen.

    Ich brauch wohl noch etwas Zeit, um das zu kappieren.
    Jedenfalls will ich das mit dem TabCtrl irgenwie durchkriegen!

    Danke nochmals, Martin

    Grüsse
    Helmut


  • Mod

    Das hat nichts mit der MFC zu tun. Gar nichts.
    Das ist mehr oder weniger Plain Windows API!

    Wirf mal den Spy++ an und schau mal ob irgendwelche Fenster mit Nachrichten bombardiert werden. Also z.B. WM_GETDLGCODE oder ähnliches.



  • Danke Martin, werd ich machen.
    So lerne ich wenigstens noch was dazu.
    Man muss im Frust eben auch die Chancen sehen.



  • Na ja ...

    ich muss wohl hier erfolglos und entnervt abschliessen.
    Mit Spy++ und anderen Sachen bin ich leider nicht zum Ziel gekommen.
    Ich versteh nicht, was da alles abgeht.

    Ich weiss nur, dass ich die Dialoge, die in das TabCtrl kommen, zwar als "Child"
    definieren muss aber nicht mit dem Attribut "Control" versehen muss.
    Andere Beispiele funktionieren auch ohne dieses Attribut.
    Und bei mir würde ja auch damit alles funktionieren, wenn nicht diese "OnFocus"
    Geschichten wären, die nun mal für jedes Eingabe-Control eine passende Tastatur
    öffnen. Zumindest bleibt so die Anwendung nicht mehr hängen (Dead LocK?).
    Und somit liegt zumindest eine Teillösung vor.

    Allerdings verhalten sich die Dialoge unter einem TabCtrl anders, als ohne,
    sonst würden diese OnFocus-Events unter dem TabCtrl ja nicht ohne einen
    physischen SetFocus ausgelöst werden.

    Und diesen Unterschied finde ich leider nicht.

    Grüsse
    Helmut


Log in to reply