Programmatically destroying poup menu

I need to destroy poup menu from my application and immideatly create
another popup menu. I tried to set WM_CANCELMODE message to menu's owner
window and the call TrackPopupMenu. Old menu is destroyed but the new fails
to create with an error code  "Popup menu already exists". Please help!
LVL 7
galkinAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

mbhaktaCommented:
Try the following method :

- Initialize m_hMenu a variable to NULL.
- Before you create the popup menu do the following :
void xxxFunction(..)
{
   if ( m_hMenu != NULL)
  {
     DestroyMenu(hMenu);
    m_hMenu = CreatePopupMenu(..);
  }
  TrackPopupMenu(..);
}

Make sure you destroy the menu before you kill the application.


0
galkinAuthor Commented:
DestroyMenu doesn't destroy popup menu
0
cnasarreCommented:
There is an undocumented API in Win16 to do this named EndMenu
(USER.187) and it seems to still exist in USER32.DLL on my
NT 4.0

void FAR PASCAL EndMenu(void);

It works for me in Win16 but I have never tried it in Win32...
0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

galkinAuthor Commented:
I tried to use this function but ispite of the fact old popup menu is destroyed , the new one fails to be created ,I got the same error code(0x5a6 - "Popup menu already active")
0
cnasarreCommented:
I'm not sure that I have understood what you try to do...
You have called TrackPopupMenu() and if the user click
on a menu item, you want to dismiss the current popup menu
and display a new one. Am I right ?

It may be possible that Windows does not allow you to
create a new popup menu from a menu item message handler but this
is only a guess

Try to post yourself a message after having EndMenu()
and create your new popup menu at that time.

Another point : Is it TrackPopupMenu() which fails or
CreateMenu() ?
0
galkinAuthor Commented:
What I am trying to do is as follows:
I create popup menu using TrackPopupMenuEx. When user higjlites certain menu item I want to destroy this menu and create the new popup menu instaed of it.
0
gelbertCommented:
Following code works fine in my test application:

CMenu* pMenu = new CMenu();

pMenu->CreatePopupMenu();

pMenu->ApendMenu( x1 );
pMenu->AppendMenu( x2 );

pMenu->TrackPopupMenu();

// if you remove these two lines then you will end up with x1, x2, x3, x4 // items in the menu
pMenu->DeleteMenu( x1 );
pMenu->DeleteMenu( x2 );

pMenu->ApendMenu( x3 );
pMenu->AppendMenu( x4 );

pMenu->TrackPopupMenu();

pMenu->DestroyMenu();

delete pMenu;

0
galkinAuthor Commented:
You delete menu ONLY when TrackPopupMenu returns it means when popup menu is destroyed but I need to destroy it from my application( when specified menu item is highlited) not by mouse clicking outside menu
0
RONSLOWCommented:
Firstly - this seems to be a BAD UI design.  If you do some action on HILIGHTING a menu item, then that makes it very difficult for the user to select items below it.  It would be better to popup the other menu when you SELECT another item (in which case there is nothing special to do).  Another alternative is to use a cascading menu for that option.

Also I am not sure how you plan to detect a highlight on given item - perhaps through owner draw?  [How ARE you planning to detect a highlight?)

Anyway, if you DO want to do this. I'd suggest you send a mouse click message to the window when you get the highlight so that the menu THINKS you have dismissed it (or selected it), and then carry on from there by displaying another popup.

Note if you simulate the mouse event that selectes the item, the popup menu will send a WM_COMMAND - and this command could popup the subsequent menu.  If you choose to simulate a dismiss (by clicking somewhere else) then you can just follow the TrackPopupMenu call with another (as in gelbert's code)

However, I still feel this is a very strange UI design and would recommend you do something more standard and make sure you have considered the implications.

0
RONSLOWCommented:
Why the reject??????

A Reject without explanation is not likely to encourage further answers.

0
RONSLOWCommented:
Are you using the word "higlight" to mean selecting an option from the menu, or simply higlighting it (moving mouse over it and the item is higlighted, but not yet selected)?

If it is the first meaning (actually select an item) then the answer is easy, because the popup disappears on its own and you can popup another in the command handler for that message.

If you mean highlight, then why not try:
* Cascading submenu.
* Alter existing menu by deleting old item and adding new ones so it is the same menu object but with different items in it.

Also, if you want to continue with the WM_CANCELMODE options, try sending that message and then posting yourself a message whose handler creates the other windows.  That way you might avoid creating the new popup before the old one is completely destroyed.

And again, I feel that this UI design is a bit odd - can you explain  why you have chosen this method - perhaps we can think of another way of doing it that actually works


0
galkinAuthor Commented:
Let me not to go deep in my apllication. I just want to underline what I need to implement. When a popup menu is displayed it captures all mouse events. I need when mouse pointer is over some hot area of menu's owner window this menu would "track" to this positions( this implementation is reqired by design of our product). I can determine where the mouse pointer by handling WM_ENTERIDLE message periodically sent by menu temporary window to its owner and calling GetCursorPos. The problem is how to destroy this popup menu?
        Thanks.
0
RONSLOWCommented:
The is NOT what you said before.  You said that the mnue was to disappear when the user higlighted a menu option, not moved somewhere else.  AND you still have not said why you rejected my answers - I think an apology is in order here !!

I am TRYING to help you, but if you change the question on me all the time it is hard.

Anyway - here is code that does exactly what you have said you wanted (in this latest comment).  When a menu is popped up, it detects movement over a hot area of the view and changes the menu accordingly.

I hope THIS is what you want and is good enought for you to accept :-)

static int CurrentMenu = 0;

void CTestView::OnEnterIdle( UINT nWhy, CWnd* pWho ) {
      if (nWhy == MSGF_MENU) {
            TRACE("EnterIdle for menu\n");
            CPoint point; ::GetCursorPos(&point);
            ScreenToClient(&point);
            CRect rect; GetClientRect(rect);
            if (point.x < rect.left+1*rect.Width()/3) {
                  if (CurrentMenu != 1) {
                        SendMessage(WM_CANCELMODE);
                        PostMessage(WM_COMMAND,ID_SHOWMENU_1);
                  }
            }
            if (point.x > rect.left+2*rect.Width()/3) {
                  if (CurrentMenu != 2) {
                        SendMessage(WM_CANCELMODE);
                        PostMessage(WM_COMMAND,ID_SHOWMENU_2);
                  }
            }
      }
      
}
void CTestView::OnLButtonDown( UINT nFlags, CPoint point ) {
      TRACE("OnLButtonDown\n");
      SendMessage(WM_COMMAND,ID_SHOWMENU_1);
}

void CTestView::OnShowMenu1() {
      TRACE("OnShowMenu1\n");
      CurrentMenu = 1;
      CPoint point; ::GetCursorPos(&point);
      CMenu menu; menu.LoadMenu(IDR_MENU1);
      CMenu* pSubMenu = menu.GetSubMenu(0);
      pSubMenu->TrackPopupMenu (TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
      CurrentMenu = 0;
}

void CTestView::OnShowMenu2() {
      TRACE("OnShowMenu2\n");
      CurrentMenu = 2;
      CPoint point; ::GetCursorPos(&point);
      CMenu menu; menu.LoadMenu(IDR_MENU2);
      CMenu* pSubMenu = menu.GetSubMenu(0);
      pSubMenu->TrackPopupMenu (TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
      CurrentMenu = 0;
}

Roger

0
galkinAuthor Commented:
I repeat I don't want to explain to you all the points of my application design. It doesn't matter. I face to pure technical problem. I need to destroy popup menu programatically, it means not by mouse and create the new one.  
0
RONSLOWCommented:
I HAVE TOLD YOU HOW TO DO IT AND YOU KEEP REJECTING ME!!!!

I have given you WORKING CODE doing EXACTLY what you said you wanted it to do. AND YOU STILL REJECTED!!

"I can determine where the mouse pointer by handling WM_ENTERIDLE message periodically sent by menu temporary window to its owner and calling GetCursorPos. The problem is how to destroy this popup menu? "

Here is my answer again.

Anyway - here is code that does exactly what you have said you wanted (in this latest comment). When a menu is popped up, it detects movement over a hot area of the view and changes the menu accordingly.

I hope THIS is what you want and is good enought for you to accept :-)

static int CurrentMenu = 0;

void CTestView::OnEnterIdle( UINT nWhy, CWnd* pWho ) {
if (nWhy == MSGF_MENU) {
TRACE("EnterIdle for menu\n");
CPoint point; ::GetCursorPos(&point);
ScreenToClient(&point);
CRect rect; GetClientRect(rect);
if (point.x < rect.left+1*rect.Width()/3) {
if (CurrentMenu != 1) {
SendMessage(WM_CANCELMODE);
PostMessage(WM_COMMAND,ID_SHOWMENU_1);
}
}
if (point.x > rect.left+2*rect.Width()/3) {
if (CurrentMenu != 2) {
SendMessage(WM_CANCELMODE);
PostMessage(WM_COMMAND,ID_SHOWMENU_2);
}
}
}

}
void CTestView::OnLButtonDown( UINT nFlags, CPoint point ) {
TRACE("OnLButtonDown\n");
SendMessage(WM_COMMAND,ID_SHOWMENU_1);
}

void CTestView::OnShowMenu1() {
TRACE("OnShowMenu1\n");
CurrentMenu = 1;
CPoint point; ::GetCursorPos(&point);
CMenu menu; menu.LoadMenu(IDR_MENU1);
CMenu* pSubMenu = menu.GetSubMenu(0);
pSubMenu->TrackPopupMenu (TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
CurrentMenu = 0;
}

void CTestView::OnShowMenu2() {
TRACE("OnShowMenu2\n");
CurrentMenu = 2;
CPoint point; ::GetCursorPos(&point);
CMenu menu; menu.LoadMenu(IDR_MENU2);
CMenu* pSubMenu = menu.GetSubMenu(0);
pSubMenu->TrackPopupMenu (TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
CurrentMenu = 0;
}

Roger


0
RONSLOWCommented:
Please either accept this answer (which shows how to destroy the menu)  or give me a good explanation of WHY it is unaceptable.

I am here to hlpe you, but you need to co-operate here so that I can.  I have take time out of my work to get the above code working and to send it to you.

0
galkinAuthor Commented:
I tried it long ago but the second menu is not created and GetLastError returned error code "Popup menu already exists"
0
RONSLOWCommented:
Did you do as I did (the above code works) and POST yourself a message after sending the WM_CANCELMODE so that any message that cancel mode generates to destroy the original popup menu have time to operate???

The code I wrote above uses WM_CANCELMODE and WORKS FINE!!.  As you said you were doing, I send the WM_CANCELMODE from within OnEnterIdle and then used PostMessage to POST myself a message about what I want to do next (create another popup).

Please try this method and see if it works for you.

If it does, let me post the answer again so you can reward me - I've worked hard for this question !!!!

Roger

0
galkinAuthor Commented:
Yes I followed your advise and and did everything as you wrote. Please send me your code and I will try to compile and build it. I expect there is some misunderstanding between us. Either I don't understand anything or you don't understund what I want to do. My E-mail address as follows: sasha@zsoft.com
0
RONSLOWCommented:
Please grade my answer again.

Thank you

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.