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: 1046Wo 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).
-
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.
-
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
-
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 CTestBuund 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

-
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();