CView / CDialog - SetOwner



  • Hallo zusammen! 🙂

    Folgendes Szenario:

    Ich habe eine MFC SDI / "einfaches Dokument" Anwendung inkl:

    CView::CDlgTest2View
    

    Aus dieser Anwendung starte ich per Menü, modal einen "Dialog1".

    void CDlgTest2View::OnFileTdm()
    {
    	// TODO: Fügen Sie hier Ihren Befehlsbehandlungscode ein.
    
    	// CArray<CWnd*, CWnd*> m_tCWnd; -> Angelegt in "DlgTest2View.h"
    
    	CMyForm1 myForm1(&m_tCWnd, this);
    	myForm1.DoModal();
    }
    

    Aus Dialog1 starte ich modal Dialog2.

    In Dialog2 erstelle ich per ButtonClick, ein/mehrere nicht modale Dialog3 Fenster.

    // class CMyForm2 : public CDialogEx
    
    void CMyForm2::OnBnClickedButton21()
    {
    //...
    	pForm3->Create(CMyForm3::IDD);
    	pForm3->ModifyStyle(NULL, WS_CHILD);
    	pForm3->SetOwner(this);
    
    	pForm3->ShowWindow(SW_SHOW);
    
    	m_ptCWnd->Add(pForm3);  // Hinzufügen zum Array
    //...
    }
    

    Wenn ich Dialog2 schließe, sollen die "Dialog3" Fenster an Dialog1 übergeben werden. Wenn man Dialog1 schließt, soll die HauptView (CDlgTest2View) die Obhut der Dialog3 Fenster übernehmen.

    Ziel ist es, dass die (nicht modalen) Dialog3 Fenster auf jeder "DialogX / CDlgTest2View" Ebene paralell zu dem jeweiligen Fenster angefasst/bewegt werden dürfen.

    Nochmal zur Übersicht:

    "CDlgTest2View" -> öffnet modal -> "Dialog1" -> öffnet modal -> "Dialog2" -> erstellt nicht-modal -> x mal "Dialog3"

    CDlgTest2View:
    Enthält ein Array in dem die "Dialog3" Fenster verwaltet werden. Dieses Array wird von Dialog zu Dialog weitergegeben:

    CArray<CWnd*, CWnd*> m_tCWnd
    

    Dialog1 und Dialog2:
    Hier greife ich in der "OnInitDialog" Methode auf das oben beschriebene "m_tCWnd" Array zu und setze in den Dialog3 Fenstern den Owner:

    BOOL CMyForm1::OnInitDialog()
    //bzw
    //BOOL CMyForm2::OnInitDialog()
    {
    ...
    	for (i = 0; i < m_ptCWnd->GetCount(); i++)
    	{
    	...
    		pForm3 = (CMyForm3 *)m_ptCWnd->GetAt(i);	
    		pForm3->SetOwner(this);
    	...
    	}
    }
    

    Wenn ich, also, von Dialog1 den Dialog2 öffne ist Dialog2 der neue Owner der Dialog3 Fenster.

    Wenn ich Dialog2 bzw. Dialog1 verlasse übergebe ich im "OnDestroy" Event des Dialogs2/1 die Dialog3 Fenster an den neuen Owner: (Dialog2->Dialog1->CDlgTest2View)

    void CMyForm1::OnDestroy()
    //bzw
    //void CMyForm2::OnDestroy()
    {
    //...
    	for (i = 0; i < m_ptCWnd->GetCount(); i++)
    	{
    	//...
    		pForm3 = (CMyForm3 *)m_ptCWnd->GetAt(i);	
    		pForm3->SetOwner(m_pParent);
    	//...
    	}
    }
    

    Das ganze hin und her Übergeben der "nicht modalen" Dialoge3 funktionert auch ganz gut zwischen Dialog2 und Dialog1 (und umgekehrt).
    Sobald ich aber die Dialoge3 von Dialog1 nach "CDlgTest2View" übergebe, dann funktioniert das Konstrukt nicht mehr, wenn ich wieder Dialog1 öffne.

    **
    Die Dialoge3 bleiben am "CDlgTest2View" 'hängen'. Ich kann von Dialog1 und Dialog2 nicht mehr auf die Dialoge3 zugreifen / anfassen / bewegen.

    Das "SetOwner" in der OnInit von Dialog1 scheint nicht mehr zu funktionieren. Also die Übergabe von CDlgTest2View -> Dialog1.
    **

    Ich hoffe, ich habe das Problem halbwegs verständlich wiedergegeben. 🙂
    Danke schon mal für eure Hilfe!


  • Mod

    Falsche Funktion.

    SetOwner ist was ganz speziell MFC internes und wird eigentlich nur für das Message Routing von Toolbars benutzt.
    Die Windows API kennt keine SetOwner Funktion!

    Schau doch selbst die Funktion an. Du hast den Sourcecode, oder debugge mal rein!

    Du musst SetParent verwenden!

    Vermutlich passiert beim zerstören der Dlg1 und Dlg2 Fenster ein automatischer Transfer der anderen Popup Fenster...



  • Hallo Martin!

    Frohes Neues und danke für deine Antwort!

    Ich habe das Problem immer noch nicht gelöst, allerdings immerhin einige Erkenntnisse gewonnen.

    Nochmal zur Übersicht:
    "CDlgTest2View" -> öffnet modal -> "Dialog1" -> öffnet modal -> "Dialog2" -> erstellt nicht-modal -> x mal "Dialog3"

    Beim Wechsel zwischen Dialog1 und Dialog2 ist kein Dialog3->SetParent(m_pParent) Aufruf notwendig. Da scheint dieser automatischer Transfer statt zu finden, den du angedeutet hast.
    Die nicht modalen Dialog3 Fenster sind dann auf der Ebene des aktuell aktiven Dialogs (1 oder 2) und dort frei bewegbar. Also alles OK!

    Von "CDlgTest2View" -> "Dialog1" bleibt die Sache weiterhin problematisch.

    Wenn ich in der Dialog1::OnInitDialog() versuche mit:

    BOOL CMyForm1::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    
    	int i = 0;
    	CMyForm3 * pForm3 = NULL;
    
    	for (i = 0; i < m_ptCWnd->GetCount(); i++)
    	{
    		pForm3 = (CMyForm3 *)m_ptCWnd->GetAt(i);		
     		//pForm3->SetOwner(this);
    
    		pForm3->SetParent(this);
    	}
    
    	return TRUE;
    }
    

    zu arbeiten bleibt das System nach ausführen von "SetParent" in der "CWnd::WindowwProc" hängen. Das Programm ist eingefroren.

    Hier ein Auszug aus der Aufrufliste:

    mfc120ud.dll!CWnd::WindowProc(unsigned int message, unsigned int wParam, long lParam) Zeile 2094 + 0x22 Bytes C++
    mfc120ud.dll!AfxCallWndProc(CWnd * pWnd, HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) Zeile 282 + 0x1e Bytes C++
    mfc120ud.dll!AfxWndProc(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) Zeile 435 C++
    mfc120ud.dll!AfxWndProcBase(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) Zeile 299 + 0x15 Bytes C++
    user32.dll!_InternalCallWinProc@20() + 0x23 Bytes
    user32.dll!_UserCallWinProcCheckWow@32() + 0xb7 Bytes
    user32.dll!_DispatchClientMessage@24() + 0x51 Bytes
    user32.dll!___fnDWORD@4() + 0x2b Bytes
    ntdll.dll!_KiUserCallbackDispatcher@12() + 0x2e Bytes
    user32.dll!_NtUserSetParent@8() + 0x15 Bytes
    mfc120ud.dll!CWnd::SetParent(CWnd * pWndNewParent) Zeile 216 + 0x18 Bytes C++
    DlgTest2.exe!CMyForm1::OnInitDialog() Zeile 77 C++


Log in to reply