Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

CTempWnd, CTempMenu

Posted on 1999-07-28
17
Medium Priority
?
554 Views
Last Modified: 2013-11-20
I have a structure with several pieces in it of type CmMenu* (a class derived from CMenu).  A pointer to this structure gets passed into a function and when I examine its contents in the debugger I find that one of the CmMenu* pieces is showing as being a CTempMenu and another piece that should be a CWnd* is of type CTempWnd.  What are these temp types?  I don't find mention of them in the documentation, but I'm still looking.  How do they get created?  Are they safe to use?  They don't seem to be, since when I return from the function my CmMenu* doesn't save the changes I make to it inside the function.
0
Comment
Question by:appleby
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
17 Comments
 
LVL 23

Expert Comment

by:chensu
ID: 1311774
Don't worry. They are defined internally in MFC as follows.

class CTempMenu : public CMenu
{
      DECLARE_DYNCREATE(CTempMenu)
      DECLARE_FIXED_ALLOC(CTempMenu);
};

class CTempWnd : public CWnd
{
      DECLARE_DYNCREATE(CTempWnd)
      DECLARE_FIXED_ALLOC(CTempWnd);
};

You can find more code in the winmenu.cpp and wincore.cpp.
0
 

Author Comment

by:appleby
ID: 1311775
The most important part of my question you did not answer, but thank you for the information provided.  I still need to know if they are safe to use, or more clearly, are they just temporary and do you lose any changes you make when you return from using them?
0
 
LVL 5

Expert Comment

by:vachooho
ID: 1311776
CTempMenu, CtempWnd and other temp objects constructed by MFC framework during the calls to some functions
such as AfxGetMainWnd(), GetDC() etc.

They are realy temporary objects and can not be used outside the scope they'd received. MFC framework will delete all those objects when an application will have an idle time.
Functions which returns such kind of objects all has the special note in MSDN.

example:
this code is incorrect and will not work
void CWndMy::OnCommand1()
{
  m_pMenu = GetMenu();
}

void CWndMy::OnCommand2()
{
  if(m_pMenu != NULL)
    m_pMenu->AppendMenu(...);
}
in OnCommand2 handler m_pMenu could be destroyed and deleted
you can not use it!

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:appleby
ID: 1311777
I see.  Thanks that clears it up.

The code where I'm getting this is after passing this structure into a function then calling some CMenu operations on the CmMenu part of the structure, like DeleteMenu().  Can you suggest a way I can do that without it creating a CTempMenu?  I need the menu items to really get deleted, and stay deleted after returning from the function.
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 1311778
Hi appleby

in fact vachooho tells the truth, but the question of loosing any changes is still not answered:

Because CWnd/CMenu are just wrapper classes for API function anything you call against CWnd/CMenu is wrapped to an API call using the CWnd's/CMenu's HWND/HMENU, so there's no danger that changes are lost.

Only danger (even with CWnd/CMenu pointers) is that one should never store a CWnd/CMenu pointer returned by (nearly, exception i.e. CWnd::FromHandlePermanent) any MFC function for later use, because most of the objects these pointers are pointing to are temporary and the framework deletes these objects when processing WM_IDLE messages. It's always a safe strategy to store the attached HWND/HMENU handle.

Example:

CWnd* pParentWnd;
HMENU hMainMenu;

----------------------------------------
CMyView::OnInitialUpdate(...)
{
...
pParentWnd = AfxGetMainFrame();
hMainMenu = pParentWnd->GetMenu()->GetSafeHmenu();
...
}

CMyView::OnAnyMessage(...)
{
...
CMenu *pMenu;
pMenu = pParentWnd->GetMenu(); // this may crash, because pParentWnd might not point to an existing object
pMenu = CMenu::FromHandle( hMainMenu ); // this is safe, cannot crash except the menu has been destroyed earlier
...
}
----------------------------------------


hope that helps,

ZOPPO
0
 

Author Comment

by:appleby
ID: 1311779
Yes, this is what I need to solve my problem.  Thank you Zoppo.  Repost an answer for the credit.
0
 
LVL 31

Accepted Solution

by:
Zoppo earned 400 total points
ID: 1311780
You're welcome ...   :)
0
 

Author Comment

by:appleby
ID: 1311781
Maybe I closed this out too soon.  :)  
I am grabbing the HMENU from my CMenu and passing that around instead of a pointer to the menu.  But within the functions, I still don't get the changes saved when I return.  Inside the function I create a temporary menu from the handle, do my work on it, then return the handle.  When I return, I get back exactly what I sent without the modifications.  What am I doing wrong?  
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 1311782
Can you post the code which does the changes ?
0
 

Author Comment

by:appleby
ID: 1311783
menus is a pointer to a class which contains member variable m_tasks, which is an HMENU.
(m_tasks was originally a CmMenu* but I changed it in trying to get this working.)

In a global function, this call is made:

      DestroyChildren( menus->m_tasks );

And DestroyChildren is defined like this, calling CMenu::DeleteMenu within it.

      extern void DestroyChildren( HMENU men )
      {
            CmMenu* tmpMen = (CmMenu*)CMenu::FromHandle(men);
            if ( !men ) return;

            for ( UINT i=0; i<tmpMen->GetMenuItemCount(); )
            {
                  tmpMen->DeleteMenu(i, MF_BYPOSITION);
            }
      }


You can see in the debugger that it does get the right number of menu items and deletes them with success, according to the return values, but when the function returns the menu is still in its original form.

I'm probably missing some vital code you want to look at - let me know.
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 1311784
Does DeleteMenu() return TRUE?

Have you tried to call CMenu::DrawMenuBar() after DestroyChildren() ? Perhaps the menu items are deleted correct and only the displayed menu is wrong.

furthermore one little hint:

instead of:
for ( UINT i=0; i<tmpMen->GetMenuItemCount(); )
{
 tmpMen->DeleteMenu(i, MF_BYPOSITION);
}

you can write:
while ( tmpMen->GetMenuItemCount() )
{
 tmpMen->DeleteMenu(0, MF_BYPOSITION);
}

it's easier to read this.

ZOPPO
0
 

Author Comment

by:appleby
ID: 1311785
Yes, DeleteMenu() does return true.  I wasn't calling DrawMenuBar() after the DestroyChildren() call, (btw, you mean CWnd::DrawMenuBar() I believe, there is none for CMenu) but it makes no difference when I try it.


0
 
LVL 31

Expert Comment

by:Zoppo
ID: 1311786
Can you post some code where the menu is created and m_tasks is set? Are you sure m_tasks is the handle to that menu the window uses?
0
 

Author Comment

by:appleby
ID: 1311787
In the OnInitialUpdate() of the view class for the class m_tasks belongs to, this code allocates space and loads the menu.  "Tasks" is a submenu on the menu when it first gets loaded.  (it is this way in the resource editor to start with.)  Then when DestroyChildren gets called as above, it removes all the items under the "Tasks" submenu, or is supposed to.

      m_pMenu = new CmMenu();
      m_pMenu->LoadMenu(IDR_FPW);
      SetMenu(m_pMenu);
      
      frame->m_tasks = m_pMenu->FindSubMenu("Tasks")->GetSafeHmenu();

I'm sure it is the right handle, because inside the DeleteMenu() function, it sees the right number of items on the menu.  That is the only menu that has 9 items on it.  
0
 

Author Comment

by:appleby
ID: 1311788
I also just checked the handle by comparing it to the m_hMenu of the CMenu* object and they are the same.
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 1311789
I do not see any problems in your code.

Is the function DestroyChildren called from another thread or module(dll)?
Have you tried to get the menu anew in DestroyChildren, i.e.

DestroyChildren( frame->GetMenu()->m_hMenu );

void DestroyChildren( HMENU men )
{
  CMenu* tmpMen = CMenu::FromHandle(men);
  tmpMen = tmpMen->FindSubMenu( "Tasks " );
  if ( !tmpMen ) return;

  for ( UINT i=0; i<tmpMen->GetMenuItemCount(); )
  {
     tmpMen->DeleteMenu(i, MF_BYPOSITION);
  }
}

0
 
LVL 31

Expert Comment

by:Zoppo
ID: 1311790
sorry, unfortunately I have to go home now (hurra, it's friday evening!!!), so I can't discuss anything more until monday morning...

have a nice weekend and try to forget your problem one or two nights, it sometimes helps...

ZOPPO
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This course is ideal for IT System Administrators working with VMware vSphere and its associated products in their company infrastructure. This course teaches you how to install and maintain this virtualization technology to store data, prevent vuln…

722 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question