Menü-Änderung auserhalb des .rc Resource Files?



  • Hallo,

    ich habe in meinem Programm einen Menü Eintrag (oben in der Datei-Bearbeiten-usw. Leiste) der nicht in meiner Program.rc Datei defiiert ist. Beim click auf diesen Menü-Eintrag, wird immer eine Assertion geschmissen und das Programm stürtz dann ab.

    Debug Assertion Failed!

    Program: Dateibaum\Program.exe
    File: afxwin1.inl
    Line: 1046

    Wo könnte dieser merkwürdige Eintrag her kommen?

    Zusätzlich wird der in meinem .rc-File linkeste Menüeintrag einfach nicht angezeigt!?!?

    Vielen Dank für jegliche Hilfe im Voraus,
    Phil



  • Vermutlich ist da was in der .rc Datei defekt. Mach Dir doch ein kleines Testprojekt, in dem Du das Menü aus Deiner Anwendung nachbaust. Anschließend vergleichst Du einfach die beiden Menü-Sektionen aus den .rc Dateien bzw. überschreibst die entsprechenden Angaben in Deinem Projekt aus dem Testprojekt (setzt natürlich voraus, dass die Menüpunkte im Testprojekt dieselben IDs haben wie in Deiner Anwendung).


  • Mod

    Dieser ASSERT hat erstmal primär nichts mit Deiner Menü-Ressource zu tun.

    Verate uns mal lieber was dass genau für ein ASSERT ist und weclhe VC Version Du verwendest.

    Ich vermute eher, du Willst ein CWnd Objekt nutzen und dieses ist in diesem Augenblick noch gar nicht erzeugt.



  • Wie meinst Du was das genau für ein Assert ist?
    Also ich nutze Visual C++ 5.0 mit Developer Studio 97... ein bisschen älter also 🙂

    Also Du meinst das beim Click auf diesen Menü Eintrag auf das CWnd Objekt zugegriffen werden soll? Weil ich will ja das der ganze Eintrag verschwindet, weiß ja nur leider überhaupt nicht wo der her kommt. Ich könnte auch mal meine .rc hier posten, falls das irgendwie behilflich ist?



  • Die MFC ist mit ASSERTs zugepflastert, um beim Debuggen mögliche Fehlerquellen schneller zu lokalisieren. Hier verwendet aber kaum noch einer VC5, deshalb kann hier keiner nachschauen, was in der afxwin1.inl an Zeile 1046 steht. Dies ist aber wichtig, um den Fehler etwas eingrenzen zu können.

    Aber Du kannst uns sicher sagen, was um dieser Stelle herum dort steht. 🙂



  • lol ja is scho recht alt... das stimmt.
    Also beim click auf retry im debug modus steht folgendes in der AFXWIN1.INL

    _AFXWIN_INLINE UINT CMenu::GetMenuItemCount() const
    	{ ASSERT(::IsMenu(m_hMenu)); return ::GetMenuItemCount(m_hMenu); }
    

    Verstehe ich das scho richtig, dass eben kein Untermenü existiert und das Programm deshalb abstürzt, ge?

    In der WINFRM.CPP steht folgendes:

    state.m_nIndexMax = pMenu->GetMenuItemCount();
    

    Macht das hier irgendwen schlauer? 😕

    Daanke! 🙂



  • Das heißt, dass m_hMenu kein gültiges Menühandle ist.

    Wie heißt denn der "überflüssige" Menüeintrag in der Leiste genau?



  • Der Menü eintrag heißt "Calibration" ...
    nach dem String zu suchen macht aber keinen Sinn, da gibt es einfach zuuu viele Dateien.


  • Mod

    pMenu ist NULL oder hat kein gültiges Menu!

    Welcher Code von Dir wird denn ausgeführt. Schau Dir mal den Callstack an!



  • Das sind die oberen Stack Zeilen nach dem klick auf Retry:

    CMenu::GetMenuItemCount() line 1046 + 46 bytes
    CFrameWnd::OnInitMenuPopup(CMenu * 0x00940700 {CMenu}, unsigned int 2, int 0) line 1402 + 8 bytes
    CWnd::OnWndMsg(unsigned int 279, unsigned int 1574269, long 2, long * 0x0012f2a4) line 1858
    CWnd::WindowProc(unsigned int 279, unsigned int 1574269, long 2) line 1575 + 30 bytes
    AfxCallWndProc(CWnd * 0x0092e900 {CMainFrame hWnd=???}, HWND__ * 0x000801dc, unsigned int 279, unsigned int 1574269, long 2) line 217 + 26 bytes
    AfxWndProc(HWND__ * 0x000801dc, unsigned int 279, unsigned int 1574269, long 2) line 371
    AfxWndProcBase(HWND__ * 0x000801dc, unsigned int 279, unsigned int 1574269, long 2) line 203 + 21 bytes



  • ... und... wird aus diesem Stack irgendjemand schlauer? Es kann doch nicht sein, dass so ein Menüeintrag nicht wegzukriegen ist!? 😞

    Wo (außer in der Resource Datei) wird denn das Menü noch "beeinflusst"?

    Danke und beste Grüße,
    Phil


  • Mod

    Das Framework kommt mit dem Menü nicht zurecht.
    Dieser Menüeintrag erscheint ja nicht von Geisterhand!
    Hast Du evtl. mit InsterMenu/InsertMenuItem herum gespielt?

    BTW: Ohne das ich weiß was für eine VS Version Du benutzt kann man Dir schwer helfen, selbst mit Stacktrace.



  • Hey also wie oben geschrieben benutze ich VS C++ 5.0 Developer Studio 97 (also scho a bissi älter).
    Ne das Problem ist, das jemand anders den Fehler verursacht hat... ich versuche nur ihn auszumärzen. *grr*
    Gibt es ne Möglichkeit die InsertMenu zu reparieren oder sowas?



  • Grase mal den gesamten Quelltext nach InsertMenu/InsertMenuItem ab.



  • Also in der TestButtons.cpp gibt es folgende Funktion:

    void CTestButtons::OnSelchangeTabs(NMHDR*,LRESULT* pResult) 
    	{
    	int curSel = m_tabs.GetCurSel();
    
    	if( curSel == m_currentPage )
    		return;
    //
    //	Hide previous selection, delete its menu entry
    //
    	CSManApp*		app = (CSManApp*)AfxGetApp();
    	CMenu*			mainMenu = AfxGetMainWnd()->GetMenu();
    	int				pos;
    
    	if( m_currentPage != -1 )
    		{
    		pos = mainMenu->GetMenuItemCount() - 2;
    		mainMenu->DeleteMenu(pos, MF_BYPOSITION);		//	remove old
    		m_pages[m_currentPage]->ShowWindow(SW_HIDE);	//	hide previous
    		}
    	else
    		pos = mainMenu->GetMenuItemCount() - 1;
    //
    //	Show new selection.
    //
    	m_pages[m_currentPage = curSel]->ShowWindow(SW_NORMAL);
    //
    //	Change height
    //
    	setTabHeight();
    //
    //	change menu entry
    //
    	CStringArray	menuKeys;
    	CMenu*			menu = new CMenu;
    	CString			tabKey = commandKey + _T("\\") + m_subKeys.ElementAt(m_currentPage);
    
    	getSubKeys(tabKey,menuKeys);
    
    	int				menuCount = menuKeys.GetSize();
    
    	menu->CreateMenu();
    	for( int m = 0; m < menuCount; m++ )
    		{
    		menu->AppendMenu(MF_STRING,m + DEVICE_TYPE_START,menuKeys.ElementAt(m));
    		}
    	mainMenu->InsertMenu(
    		pos,
    		MF_STRING | MF_BYPOSITION | MF_POPUP,
    		(unsigned int)menu->GetSafeHmenu(),
    		m_subKeys.ElementAt(m_currentPage));
    	AfxGetMainWnd()->DrawMenuBar();
    	delete menu;
    //
    	if( pResult )
    		*pResult = 0;
    }		//	end of CTestBu
    

    und in CMenu in der AFXWIN.H steht:

    BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT nIDNewItem = 0,
    					LPCTSTR lpszNewItem = NULL);
    	BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT nIDNewItem,
    					const CBitmap* pBmp);
    

    Bin ich da auf dem richtigen Dampfer? Oder komplett verkehrt? 😕



  • Scheint der richtige Dampfer zu sein. Helfen sollte

    AfxGetMainWnd()->DrawMenuBar(); 
    menu->Detach(); // -> Add
    delete menu;
    


  • Uuuäääähhhh! !?! Wie kommt man auf sowas?? Genial es funktioniert und ein ganzes Menü erscheint! 🙂

    Ehrlich ... wie kommt man auf diese Lösungen?

    Tausend Dank sri... wirklich, tausend Dank! 🙂

    Unglaublich *kopf.schüttel* 🙂

    Phil



  • phil_z schrieb:

    Ehrlich ... wie kommt man auf diese Lösungen?

    Meistens, weil man selbst schon mal den gleichen Fehler gemacht hat 😃


  • Mod

    phil_z schrieb:

    Uuuäääähhhh! !?! Wie kommt man auf sowas?? Genial es funktioniert und ein ganzes Menü erscheint! 🙂
    Ehrlich ... wie kommt man auf diese Lösungen?
    Tausend Dank sri... wirklich, tausend Dank! 🙂
    Unglaublich *kopf.schüttel* 🙂

    Du hast ein Objekt erzeugt mit CreateMenu. Dieses Objekt weist Du einem aktiven Menu zu und zerstörst es durch den delete.
    Das Menühandlör fliegt auf die Schnautze wenn er dieses zerstörte Menü angezeigen soll.
    Detach verhindert, dass das zugewiesene Objekt zerstört wird.

    Detach muss immer verwendet werden wenn ein Handle nich mehr an ein Objekt gebunden ist und andersweitig (z.B. in der Win32 API) verwaltet wird.

    Aber mal grundsätzlich:
    Warum veränderst Du das Menü sofort undimmer, warum veränderst Du das Menü nicht est dann, wenn es auch benötigt wird und aufgeklappt wird?
    Schau Dir mal den Code an, den die MFC verwendet um die LRU-Files Liste zu verwalten.

    Siehe sourcecode filelist.cpp
    void CRecentFileList::UpdateMenu(CCmdUI* pCmdUI)

    Dort wird ein Dummy Entrag durch eine Liste von Commands mit InsertMenu (hir nurnoch einzelne Items) ersetzt.



  • Im Prinzip hat Martin schon alles gesagt. Mit mainMenu->InsertMenu fügst Du das neu erstellte Menü in das Hauptmenü ein. Das Menühandle fällt damit in den Zuständigkeitsbereich des Hauptmenüs und wird automatisch bei Löschen des Hauptmenüs freigegeben. Durch delete menu wird es aber schon vorher gelöscht und das im Hauptmenü steckende Handle ist ungültig (daher das ASSERT).

    Deshalb muss man dafür sorgen, dass menu zwar gelöscht wird, das Windows-Handle aber erhalten bleibt. Dafür verwendet man in der Regel Detach.

    Ich selbst würde hier auf das dynamische CMenu verzichten und stattdessen eine lokale CMenu-Instanz erstellen. Zudem kann man das Detach auch gleich bei mainMenu->InsertMenu verwenden:

    //
    //    change menu entry
    //
        CStringArray    menuKeys;
        CMenu            menu;
        CString            tabKey = commandKey + _T("\\") + m_subKeys.ElementAt(m_currentPage);
    
        getSubKeys(tabKey,menuKeys);
    
        int                menuCount = menuKeys.GetSize();
    
        menu.CreateMenu();
        for( int m = 0; m < menuCount; m++ )
            {
            menu.AppendMenu(MF_STRING,m + DEVICE_TYPE_START,menuKeys.ElementAt(m));
            }
        mainMenu->InsertMenu(
            pos,
            MF_STRING | MF_BYPOSITION | MF_POPUP,
            (unsigned int)menu.Detach(),
            m_subKeys.ElementAt(m_currentPage));
        AfxGetMainWnd()->DrawMenuBar();
    

Anmelden zum Antworten