I have a simple example for creating popup menu. I want to close this menu programmatically when pressing on button, is there any possibility to do that? Or maybe I should use different class?
I need to open this menu when button is pressed and close it the same way when pressing the button. Here is simple code example that I have.
#define MAX_LOADSTRING 100
#define IDM_FILE_NEW 1
#define IDM_FILE_OPEN 2
#define IDM_FILE_QUIT 3
#define BUTTON_ID 1
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
HWND gButton = NULL;
HWND mainHwnd = NULL;
HMENU hMenu;
bool gMenuHidden = false;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_POPUPMENU, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_POPUPMENU));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_POPUPMENU));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
mainHwnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!mainHwnd)
{
return FALSE;
}
ShowWindow(mainHwnd, nCmdShow);
UpdateWindow(mainHwnd);
return TRUE;
}
HMENU CreateAndInitializeMenu()
{
HMENU menu = CreatePopupMenu();
AppendMenuW(menu, MF_STRING, IDM_FILE_NEW, L"&New");
AppendMenuW(menu, MF_STRING, IDM_FILE_OPEN, L"&Open");
AppendMenuW(menu, MF_SEPARATOR, 0, NULL);
AppendMenuW(menu, MF_STRING, IDM_FILE_QUIT, L"&Quit");
return menu;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_COMMAND:
{
if (wParam == BUTTON_ID)
{
//gMenuHidden = !gMenuHidden;
if (gMenuHidden)
{
hMenu = CreateAndInitializeMenu();
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, 150, 250, 0, mainHwnd, NULL);
DestroyMenu(hMenu);
}
else
{
// TODO:
}
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE:
{
gButton = CreateWindowW(L"button", L"Show/Hide menu", WS_VISIBLE | WS_CHILD, 100, 120, 120, 25, hWnd, (HMENU)BUTTON_ID, NULL, NULL);
break;
}
}
return DefWindowProcW(hWnd, message, wParam, lParam);
}
Maybe the right way is to always create menu when button is pressed and destroy it right after that? But in that case we should create menu all the time when pressing the button. I was trying to create the menu once and show it when we need it. Also the menu is not shown right now. Trying to figure out why. Thanks in advance.