i did these menu class:

class Menu
{
private:
    static int intID;
    int ID=0;
    bool primeiromenu=false;
    HMENU MenuHandle=NULL;
    HMENU hMenu=NULL;
    int menuposition=0;
    string strCaption="";
    public:
    Menu(string caption="&Menu",HMENU subtmenu=NULL, HWND MainHWND=WindowMain)
    {
        intID=intID+1;
        ID=intID;
        if(caption!="-")
            caption=(string)caption + " " + to_string(ID);
        strCaption=caption;
        if(GetMenu(MainHWND)==NULL)
            hMenu = CreateMenu();
        else
            hMenu =GetMenu(MainHWND);
        if (subtmenu==NULL)
        {
            HMENU hSubMenu=CreatePopupMenu() ;
            AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, caption.c_str());
            MenuHandle=hSubMenu;//my error was here
            SetMenu(MainHWND, hMenu);
            menuposition=GetMenuItemCount(hMenu)-1;
            primeiromenu=true;
        }
        else
        {
            if(caption=="-")
                AppendMenu(subtmenu, MF_SEPARATOR, ID, caption.c_str());
            else
                AppendMenu(subtmenu, MF_STRING, ID, caption.c_str());
            MenuHandle=subtmenu;
            menuposition=GetMenuItemCount(subtmenu)-1;
            SetMenu(MainHWND, hMenu);
        }
    }

    void Show(HWND mainshowed)
    {
        LPPOINT x;
        GetCursorPos(x);
        SetForegroundWindow(mainshowed);
        TrackPopupMenu(MenuHandle,NULL,x->x,x->y,0,mainshowed,NULL);
        PostMessage(mainshowed, WM_NULL, 0, 0);
    }

    int getmenuposition()
    {
        return menuposition;
    }

    property<string> Caption
    {
        Get(string)
        {
            return strCaption;

        },
        Set(string text)
        {
            MENUITEMINFO mi;
            mi.cbSize=sizeof(MENUITEMINFO);
            if(primeiromenu==true)
                GetMenuItemInfo(GetMenu(WindowMain),menuposition,true,&mi);
            else
                GetMenuItemInfo(MenuHandle,menuposition,true,&mi);
            mi.fMask=MIIM_STRING;
            mi.dwTypeData =(LPTSTR)text.c_str();
            if(primeiromenu==true)
                SetMenuItemInfo(GetMenu(WindowMain),menuposition,true,&mi);
            else
                SetMenuItemInfo(MenuHandle,menuposition,true,&mi);

        }
    };

    operator int()
    {
        return ID;
    }

    operator HMENU()
    {
        return MenuHandle;
    }
    void Destroy()
    {
        DestroyMenu(MenuHandle);
    }
};
int Menu::intID=0;

the function Show only show me the menu rectangle... and the OS close the program. what i'm doing wrong?

Recommended Answers

All 6 Replies

Is this Visual Studio C++? C++/CLI? I ask because you have "property" and "get, set" syntax which matches that of C#..

triumphost: sorry about that. it's my own property class with 2 macros ;)
i'm using C/C++11 with Code Blocks.

i resolve the problem. the popup menu is showed ;)

void Show(HWND mainshowed)
    {
        POINT  p;
        GetCursorPos(&p);
        SetForegroundWindow(mainshowed);
        TrackPopupMenu(MenuHandle,NULL,p.x,p.y,0,mainshowed,NULL);
        PostMessage(mainshowed, WM_NULL, 0, 0);
    }

but i have some problems for subclassing the procedure messages :(

Menu(string caption="&Menu",HMENU subtmenu=NULL, HWND MainHWND=WindowMain)
    {
        intID=intID+1;
        ID=intID;
        if(caption!="-")
            caption=(string)caption + " " + to_string(ID);
        strCaption=caption;
        if(GetMenu(MainHWND)==NULL)
            hMenu = CreateMenu();
        else
            hMenu =GetMenu(MainHWND);
        if (subtmenu==NULL)
        {
            HMENU hSubMenu=CreatePopupMenu() ;
            AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, caption.c_str());
            MenuHandle=hSubMenu;//my error was here
            SetMenu(MainHWND, hMenu);
            menuposition=GetMenuItemCount(hMenu)-1;
            primeiromenu=true;
        }
        else
        {
            if(caption=="-")
                AppendMenu(subtmenu, MF_SEPARATOR, ID, caption.c_str());
            else
                AppendMenu(subtmenu, MF_STRING, ID, caption.c_str());
            MenuHandle=subtmenu;
            menuposition=GetMenuItemCount(subtmenu)-1;
            SetMenu(MainHWND, hMenu);
        }

        SetWindowLong(MainHWND,GWL_WNDPROC,(LONG)MenuSubclassProc);
        SetWindowLong(MainHWND,GWL_USERDATA,(LONG)this);

    }
    //the MainHWND is the form handle. in these case i think is wrong, 
    //but i don't know get the menu HWND from HMENU :(

    //the message procedure:
    static LRESULT CALLBACK MenuSubclassProc( HWND hwnd, UINT uMsg, WPARAM wParam,  LPARAM lParam)
    {
       Menu *wnd = 0;

        // retrieve associated Window instance
        wnd = reinterpret_cast<Menu *>(GetWindowLong(hwnd, GWL_USERDATA));
        if(uMsg==WM_COMMAND)
            wnd->MenuClick();//the MenuClick it's a lambda variable
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

and in form window procedure message i have:

case WM_COMMAND:
                {
                    //inst->MenuClick((int)wParam) ;

                    SendMessage((HWND)lParam , WM_COMMAND, wParam, lParam);
                }
                break;

advice me more.

Have a read of MSDN for the WM_COMMAND message. For a menu, only the menu identifier is passed via the low word of the wParam, the lParam is zero.
So your code:
SendMessage((HWND)lParam , WM_COMMAND, wParam, lParam) will be equivalent to
SendMessage((HWND)OL , WM_COMMAND, wParam, 0L)

nullptr so how can i send the message?

The HWND parameter is a handle to the window that owns the menu..

PostMessage(ApplicationWindowHandle, WM_COMMAND, MenuID, 0);

will work.

Example (You can use this if you like but I don't recommend doing it this "exact" way [specifically the "FindMenuItem" part]):

#include <windows.h>
#include <string>
#include <vector>
#include <tchar.h>
#include <iostream>

class MenuBar
{
    private:
        HMENU ID;
        HWND Parent;
        std::vector<HMENU> Menus;

    public:
        MenuBar();
        MenuBar(const MenuBar &M) = delete;
        MenuBar(HWND Parent);
        virtual ~MenuBar();

        std::string GetText(HMENU Menu, int Position);
        HMENU FindMenuItem(std::string MenuName);
        HMENU FindMenuItem(HMENU Parent, std::string MenuName);

        void CreateSubMenu(HMENU Parent, std::string Name, DWORD Style);
        void AddMenuItem(std::string Name, DWORD Style);
        void AppendMenuItem(HMENU Parent, std::string Name, DWORD Style);

        HWND GetParent() const;
        void Show();

        MenuBar& operator = (const MenuBar &M) = delete;
};

MenuBar::~MenuBar() {}

MenuBar::MenuBar() : ID(nullptr), Parent(nullptr), Menus() {};

MenuBar::MenuBar(HWND Parent) : ID(nullptr), Parent(Parent), Menus()
{
    Menus.push_back(CreateMenu());
}

std::string MenuBar::GetText(HMENU Menu, int Position)
{
    TCHAR Buffer[1024] = {0};
    MENUITEMINFO MenuInfo = {0};
    MenuInfo.cbSize = sizeof(MenuInfo);
    MenuInfo.fMask = MIIM_TYPE;
    MenuInfo.fType = MFT_STRING;
    MenuInfo.cch = sizeof(Buffer);
    MenuInfo.dwTypeData = Buffer;
    if (GetMenuItemInfo(Menu, Position, true, &MenuInfo))
    {
        return Buffer;
    }
    return std::string();
}

HMENU MenuBar::FindMenuItem(std::string MenuName)
{
    for (std::size_t I = 0; I < Menus.size(); ++I)
    {
        if (MenuName == GetText(Menus.front(), I))
        {
            return GetSubMenu(Menus.front(), I);
        }
    }
    return nullptr;
}

HMENU MenuBar::FindMenuItem(HMENU Parent, std::string MenuName)
{
    std::size_t Count = GetMenuItemCount(Parent);
    for (std::size_t I = 0; I < Count; ++I)
    {
        if (MenuName == GetText(Parent, I))
        {
            return GetSubMenu(Parent, I);
        }
    }
    return nullptr;
}

void MenuBar::CreateSubMenu(HMENU Parent, std::string Name, DWORD Style)
{
    Menus.push_back(CreatePopupMenu());
    AppendMenu(Parent, Style, reinterpret_cast<UINT_PTR>(Menus.back()), Name.c_str());
}

void MenuBar::AddMenuItem(std::string Name, DWORD Style)
{
    Menus.push_back(CreateMenu());
    MENUINFO MenuInfo = {0};
    MenuInfo.cbSize = sizeof(MenuInfo);
    MenuInfo.fMask = MIM_STYLE;
    GetMenuInfo(Menus.back(), &MenuInfo);
    MenuInfo.dwStyle |= MNS_NOTIFYBYPOS;
    SetMenuInfo(Menus.back(), &MenuInfo);
    AppendMenu(Menus.front(), Style, reinterpret_cast<UINT_PTR>(Menus.back()), Name.c_str());
}

void MenuBar::AppendMenuItem(HMENU Parent, std::string Name, DWORD Style)
{
    static int ID = 0;
    AppendMenu(Parent, Style, ++ID, Name.c_str());
}

HWND MenuBar::GetParent() const
{
    return Parent;
}

void MenuBar::Show()
{
    SetMenu(GetParent(), Menus.front());
}


LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
TCHAR szClassName[] = _T("CodeBlocksWindowsApp");

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    HWND hwnd;
    MSG messages;
    WNDCLASSEX wincl;
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof (WNDCLASSEX);
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    if (!RegisterClassEx (&wincl))
        return 0;
    hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               _T("Code::Blocks Template Windows App"),       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               544,                 /* The programs width */
               375,                 /* and height in pixels */
               HWND_DESKTOP,
               NULL,
               hThisInstance,
               NULL
           );

    ShowWindow (hwnd, nCmdShow);
    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    return messages.wParam;
}




LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static MenuBar* Mnb = nullptr;

    switch (message)
    {
        case WM_CREATE:
        {
            Mnb = new MenuBar(hwnd);
            Mnb->AddMenuItem("File", MF_POPUP);
            Mnb->AddMenuItem("Edit", MF_POPUP);
            Mnb->AddMenuItem("View", MF_POPUP);
            Mnb->AddMenuItem("Settings", MF_POPUP);
            Mnb->AddMenuItem("Help", MF_POPUP);

            HMENU FileMenu = Mnb->FindMenuItem("File");
            Mnb->CreateSubMenu(FileMenu, "Status", MF_POPUP);
            Mnb->AppendMenuItem(FileMenu, "Separator", MF_SEPARATOR);
            Mnb->AppendMenuItem(FileMenu, "Invite Contact", MF_STRING);
            Mnb->AppendMenuItem(FileMenu, "Close", MF_STRING);

            HMENU StatusMenu = Mnb->FindMenuItem(FileMenu, "Status");
            Mnb->AppendMenuItem(StatusMenu, "Online", MF_STRING);
            Mnb->AppendMenuItem(StatusMenu, "Away", MF_STRING);
            Mnb->AppendMenuItem(StatusMenu, "Busy", MF_STRING);
            Mnb->AppendMenuItem(StatusMenu, "Invisible", MF_STRING);

            HMENU EditMenu = Mnb->FindMenuItem("Edit");
            Mnb->AppendMenuItem(EditMenu, "Undo", MF_STRING);
            Mnb->AppendMenuItem(EditMenu, "Redo", MF_STRING);
            Mnb->AppendMenuItem(EditMenu, "Separator", MF_SEPARATOR);
            Mnb->AppendMenuItem(EditMenu, "Cut", MF_STRING);
            Mnb->AppendMenuItem(EditMenu, "Copy", MF_STRING);
            Mnb->AppendMenuItem(EditMenu, "Paste", MF_STRING);
            Mnb->AppendMenuItem(EditMenu, "Paste Special", MF_STRING);

            HMENU ViewMenu = Mnb->FindMenuItem("View");
            Mnb->CreateSubMenu(ViewMenu, "Display", MF_POPUP);
            Mnb->AppendMenuItem(ViewMenu, "Show Contacts", MF_STRING | MF_CHECKED);
            Mnb->AppendMenuItem(ViewMenu, "Status Bar", MF_STRING | MF_CHECKED);
            Mnb->AppendMenuItem(Mnb->FindMenuItem(ViewMenu, "Display"), "Display Picture", MF_STRING | MF_CHECKED);
            Mnb->AppendMenuItem(Mnb->FindMenuItem(ViewMenu, "Display"), "Contact Picture", MF_STRING | MF_CHECKED);

            HMENU SettingsMenu = Mnb->FindMenuItem("Settings");
            Mnb->AppendMenuItem(SettingsMenu, "Change Picture", MF_STRING);
            Mnb->Show();
        }
        break;

        case WM_COMMAND:
        {
            if (wParam == 2)
            {
                PostMessage(hwnd, WM_COMMAND, 3, lParam); //Send Message to the close menu if the invite menu is clicked..
            }

            if (Mnb->GetText(Mnb->FindMenuItem("File"), wParam) == "Close")
            {
                std::cout<<"Closing Application\n";
                PostMessage(hwnd, WM_CLOSE, 0, 0);
            }
        }
        break;

        case WM_DESTROY:
        {
            delete Mnb;
            Mnb = nullptr;
            PostQuitMessage(0);
        }
        break;

        default:
            return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

sorry i continue with problems(thats why i came up with another idea) :(
i did in these way:

//when i create the menu item:
 //put the this on dwItemData
 MENUITEMINFO  s;
 GetMenuItemInfo (hMenu,intID, true, &s);
 s.cbSize=sizeof(MENUITEMINFO );
 s.fMask=MIIM_DATA;
 s.dwItemData=(ULONG_PTR)this;
 SetMenuItemInfo (hMenu,intID, true, &s);

//change the menu for use the WM_MENUCOMMAND
MENUINFO mnInfo;
GetMenuInfo(hMenu,&mnInfo);
mnInfo.cbSize=sizeof(MENUINFO);
mnInfo.fMask=MIM_STYLE;
mnInfo.dwStyle=MNS_NOTIFYBYPOS;
SetMenuInfo(hMenu,&mnInfo);

and with WM_MENUCOMMAND in main window:

case WM_MENUCOMMAND:
{
BOOL fResult = FALSE;
MENUITEMINFO menuInfo = { 0 };

menuInfo.cbSize = sizeof(MENUITEMINFO);
menuInfo.fMask = MIIM_ID | MIIM_DATA;

fResult = GetMenuItemInfo((HMENU)lParam,(UINT) wParam, TRUE, &menuInfo );

if (fResult!=0)
{
UINT myId = menuInfo.wID; // this is item ID
ULONG_PTR myData = menuInfo.dwItemData; // item data (like 'this' pointer')
CREATESTRUCT *p = (CREATESTRUCT *)(ULONG_PTR)(menuInfo.dwItemData);
Menu *mMenu = (Menu*)p->lpCreateParams;
//if(mMenu->MenuClick==NULL) break;
mMenu->MenuClick();//it's a lambda function variable
}                    
}

but i don't get the 'this' pointer correctly, why?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.