Avatar of MentatDewd
MentatDewd

asked on 

System menus only work once...

Hi, Ok, the current problem is I load an arbitrary applications version of the system menu with the following:

      CMenu *cMenu = CWnd::FromHandle(m_ApplicationHWnd)->GetSystemMenu(FALSE);
      HMENU hMenu = cMenu->GetSafeHmenu();
      cMenu->Detach();

m_ApplicationHWnd is an arbitrary Applications hWnd. This code is part of OnContextMenu for a control derived from an owner drawn CButton. The first time my app runs, the cMenu I get is valid. If I exit and restart my app, the cMenu I get appears to be valid, but the call to GetSafeHmenu fails with an assertion. It appears that GetSafeHmenu doesn't think the m_hMenu in cMenu is valid. What is causing this behaviour? I have struggled with this for days, and nothing is working here. Any and all help is urgently needed. Thanks!!!!
System Programming

Avatar of undefined
Last Comment
CetusMOD
Avatar of Zoppo
Zoppo
Flag of Germany image

Hi MentatDewd,


I think problem hasn't to do with the code fragment you posted ...

Maybe the more relevant part of your code is the part which uses this menu ... could you post the complete OnContextMenu handler?

One other thing: IMO you don't need the 'cMenu->Detach' ... but this doesn't make a difference for this issue ....


ZOPPO
Avatar of Member_2_1001466
Member_2_1001466

Can it be that the return value of the call to
CWnd::FromHandle is a temporary object? In that case all following calls might (or will?) fail.
Use FromHandlePermanent instead. If it can't return a non temporary object it returns NULL and you immediatly see that it failed.
Only you need to check the return value before calling GetSystemMenu ()!
Avatar of MentatDewd
MentatDewd

ASKER

Ok here it is...

OnContextMenu(CWnd pWnd, CPoint point)
{
ShowMenu(point);
}

ShowMenu(POINT point)
{
CMenu *cMenu = CWnd::FromHandle(m_ApplicationHWnd)->GetSystemMenu(FALSE);
HMENU hMenu = cMenu->GetSafeHmenu();
cMenu->Detach();

::SetForegroundWindow(m_hWnd);

bRet = ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, point.x, point.y, 0, m_hWnd, NULL);

return TRUE;
}

Quite simple really, but still fails...Thanks for looking at it so far!!!

Avatar of Zoppo
Zoppo
Flag of Germany image

hm ... sorry, but I can't find any problem ... even the little testapp I wrote does the same very well ...

maybe you can put your project anywhere we can download it to test it ...

ZOPPO
The code you show still can return a temporary CWnd pointer which will let this code fail. You need to check!
See
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_cwnd.3a3a.fromhandle.asp
for my comment.

How do you get the value of m_ApplicationHWnd? Can this value be outdated or overwritten or you have no access rights to get its memory space?
Avatar of Zoppo
Zoppo
Flag of Germany image

SteH, the returned CWnd* from CWnd::FromHandled isn't stored for later use, so I don't see
how this could be the problem ... as long as m_ApplicationHWnd is a valid handle for the required
window this is IMO ok ...

The only cause for the described symptoms IMO could be that the application somehow destroyes the
menu of the other application ... this is IMO the only possibility how this problem can occur even after
the application was closed and restarted.

MentatDewd: Does it work ok again (at least once) when you close and restart the application which
owns the menu?

Avatar of MentatDewd
MentatDewd

ASKER

Yes, it does work again after I close and restart the application which owns the menu. Also, I have stopped using CMenus, and CWnds, and now use exclusively HWND and HMENU and their appropriate functions.

Sequence is:
Start my application
Create button and associate some other application's hwnd with it
Right Click on button
Show system menu from other application. <---WORKS
Do something else (i.e. cause the menu to pop down)
Show system menu from same other application <--WORKS
Do something else again (again, anything that would normally cause a menu to pop down)
Exit my application

Start my application
Create button and associate some other application's hwnd with it
Right click on button
Show system menu from same other application as in first run. <--FAILS
Right click on button
Show system menu from same other application as in first run <--FAILS

I retrieve the applications hwnd during an enumwindows call, during which I filter out only app windows which would not appear on the system taskbar, and use only the hwnds which would appear on the system taskbar.

If I don't show the other applications system menu (the user never requests it), and I exit my application, and then the user restarts my application, the menu will work when the user requests it, but if the user now exits my application and then restarts it again ::GetSystemMenu returns the same HMENU as it did when the code was functioning, but all calls using this HMENU (which are the exact same calls as the first time my application was run) are rejected as having a bad handle.

Once a valid looking bad handle is returned, my application will always fail as documented above when retrieving the system menu owned the the other application, even if I exit and restart. Note that the first time I get a valid looking bad HMENU is always on the 2nd run of the application, and only if the user had right clicked on my button (WM_CONTEXTMENU) during the previous run.

Also note that even after my application begins to fail, I can right click on either the system taskbar button for the other application, or on the other application's caption and the system menu pops up. This seems to indicate that I haven't destroyed the other applications system menu.

I know my calls are good, since this does work the first time my application runs. The system menus are even available  again when the user exits and restarts my application as long as the user hasn't yet caused me to load the other applications system menu. It seems that the action of GetSystemMenu and TrackPopupMenu causes these exact same calls to fail (GetSystemMenu returns what appears to be a valid system menu handle and is in fact the exact same handle I got on the first run of my application, and TrackPopupMenu returns a bad handle error).

Avatar of Surya Bobbadhi
Surya Bobbadhi
Flag of India image

CMenu *cMenu = CWnd::FromHandle(m_ApplicationHWnd)->GetSystemMenu(FALSE);
HMENU hMenu = cMenu->GetSafeHmenu();
cMenu->Detach();

The function CWnd::FromHandle
Returns a pointer to a CWnd object when given a handle to a window. If a CWnd object is not attached to the handle, a temporary CWnd object is created and attached. If a temporary CWnd object is created calling GetSystemMenu may return invalid menu which inturn may create a problem so first check whether your m_ApplicationHWnd is always valid.

-Surya.

Avatar of MentatDewd
MentatDewd

ASKER

Code is currently:

BOOL
CTaskButton::ShowMenu(POINT point)
{
      ASSERT (m_cTaskbar);

      TRACE0("CTaskButton::ShowMenu\n");
      POPTIONS pOptions = m_cTaskbar->GetAppbarData();
      BOOL bRet;

      HMENU hMenu = ::GetSystemMenu(m_ApplicationHWnd, FALSE);

      ::SetForegroundWindow(m_hWnd);

      bRet = ::TrackPopupMenu(hMenu,
                  TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,                                    point.x,
                  point.y,
                  0,
                  m_hWnd,
                  NULL);

Note that I am not using MFC.

Window handles for m_ApplicationHWnd are from a call to enumwindows, all are valid. Remember, this code works the first time through, and only after you exit my application and restart it, and attempt to examine an applications menu again. Other windows which may not have had their menus displayed on the first run will work on this run, but not subsequent runs.


Avatar of MentatDewd
MentatDewd

ASKER

New information, this now only seems to happen with explorer windows. All other windows work. For all other windows, I can get their system menu, and use it, but for explorer windows I can only get their system menus on a single run of my program, after that I get the symptoms described above. Non explorer windows work correctly every time.
ASKER CERTIFIED SOLUTION
Avatar of CetusMOD
CetusMOD
Flag of Netherlands image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
System Programming
System Programming

Kernel and system programming is the process of creating the software necessary for a computer or device to function and operate other programs. Some operating systems (such as Microsoft Windows) are proprietary, but others, such as the various Linux distributions, are open source.

41K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo