diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index bbaddbcf68..1704892306 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -732,6 +732,8 @@ void wxMenuItem::SetItemLabel(const wxString& txt) void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked) { + static bool s_insideSetBitmap = false; + if ( bChecked ) { if ( m_bmpChecked.IsSameAs(bmp) ) @@ -747,6 +749,18 @@ void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked) m_bmpUnchecked = bmp; } + if (s_insideSetBitmap) + { + // We can arrive here because of calling GetHBitmapForMenu + // further down below, which itself can call [Do]SetBitmap + // resulting in infinite recursion. After having set the + // bitmap just return instead. + return; + } + + wxON_BLOCK_EXIT_SET(s_insideSetBitmap, false); + s_insideSetBitmap = true; + #if wxUSE_OWNER_DRAWN // already marked as owner-drawn, cannot be reverted if ( IsOwnerDrawn() ) diff --git a/tests/menu/menu.cpp b/tests/menu/menu.cpp index 2f67765771..0ae436f27f 100644 --- a/tests/menu/menu.cpp +++ b/tests/menu/menu.cpp @@ -88,6 +88,7 @@ private: CPPUNIT_TEST( Labels ); CPPUNIT_TEST( RadioItems ); CPPUNIT_TEST( RemoveAdd ); + CPPUNIT_TEST( ChangeBitmap ); WXUISIM_TEST( Events ); CPPUNIT_TEST_SUITE_END(); @@ -100,6 +101,7 @@ private: void Labels(); void RadioItems(); void RemoveAdd(); + void ChangeBitmap(); void Events(); wxFrame* m_frame; @@ -405,6 +407,22 @@ void MenuTestCase::RemoveAdd() menu0->Delete(item); } +void MenuTestCase::ChangeBitmap() +{ + wxMenu *menu = new wxMenu; + + wxMenuItem *item = new wxMenuItem(menu, wxID_ANY, "Item"); + menu->Append(item); + + // On Windows Vista (and later) calling SetBitmap, *after* the menu + // item has already been added, used to result in a stack overflow: + // [Do]SetBitmap can call GetHBitmapForMenu which will call SetBitmap + // again etc... + item->SetBitmap( wxBitmap(1, 1) ); + + wxDELETE(menu); +} + void MenuTestCase::Events() { #ifdef __WXGTK__