Sign in to follow this  
plywood

Windows Menu Creation

Recommended Posts

The MSDN docs for making Windows menus is a *leedle* confusing... At some point, the hierarchy must look something like this: Menubar -->Menu ---->MenuItem (or SubMenu, etc.) Let's say that I want a very simple menubar, for instance, one with only a File menu, and with that sole File menu only have one command item itself, say, Exit. I am confused about creating this menu programmatically, that is, in the code, without the use of resource files or templates. Where/when do I use the following various functions: (1) HMENU file = CreateMenu(); (2) HMENU exit = CreatePopupMenu(); (3) InsertMenu() or AppendMenu() (which one?) Where do I specify the MENUINFO for each menu, such as to give the file menu the static text label of "&File"? Where/how do I define each Menu/MenuItem's ID? (e.g., IDM_FILE) Basically I just need a litle TLC on how to create and init Menus so that when my WndProc receives a WM_COMMAND, and interrogates the msg's wParam's LOWORD (thus getting the Menu ID), I can tell it what to do... I feel like I'm close, I'm just missing a few mental connections here.

Share this post


Link to post
Share on other sites
Have you tried this ? Or you are mentioning exactly that one is confusing?

Quote:
creating this menu programmatically

make sure you understand it's consequence first before doing so.
I tried, should be something like:

#include <windows.h>
#include <windowsx.h> // for macro GET_X_LPARAM() & GET_Y_LPARAM()
#include "resource.h"

LRESULT APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ;
VOID APIENTRY HandlePopupMenu(HWND hwnd, POINT pt);
BOOL WINAPI OnContextMenu(HWND hwnd, int x, int y);
VOID APIENTRY DisplayContextMenu(HWND hwnd, POINT pt);
VOID MakeChartMenu(HWND);
VOID MakeLineMenu(HWND, HPEN, HBITMAP);
HINSTANCE hinst;

int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg; // message
WNDCLASS wc; // windowclass data
HWND hwnd; // handle to the main window

// Create the window class for the main window. Specify
// the identifier of the menu-template resource as the
// lpszMenuName member of the WNDCLASS structure to create
// the class menu.

wc.style = 0;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wc.lpszClassName = "MainWClass";

if (!RegisterClass(&wc))
return FALSE;

hinst = hinstance;

// Create the main window. Set the hmenu parameter to NULL so
// that the system uses the class menu for the window.

hwnd = CreateWindow("MainWClass", "Sample Application",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance,
NULL);

if (hwnd == NULL)
return FALSE;

// Make the window visible and send a WM_PAINT message to the
// window procedure.

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// Start the main message loop.

// ms-help://MS.MSDNQTR.v90.en/wceshellui5/html/wce50lrfGetMessage.htm
// Nonzero indicates that the function retrieves a message other than WM_QUIT.
// Zero indicates that the function retrieves the WM_QUIT message, or that lpMsg is an invalid pointer.
//while (GetMessage(&msg, NULL, 0, 0) != 0 && GetMessage(&msg, (HWND) NULL, 0, 0) != -1) //failed
//while( GetMessage(&msg, NULL, 0, 0) ) // OK
//while (GetMessage(&msg, NULL, 0, 0) != 0 && GetMessage(&msg, NULL, 0, 0) != -1) //failed
while (GetMessage(&msg, NULL, 0, 0) != 0) // OK
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
UNREFERENCED_PARAMETER(hPrevInstance);
}


LRESULT APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
RECT rc; // client area
POINT pt; // location of mouse click
HMENU hmenu; // menu template
HMENU hmenuTrackPopup; // shortcut menu
static HPEN hpen[CPENS];
static HBITMAP hbmp[CPENS];
int i;

switch (uMsg)
{
// Process other window messages.
case WM_CREATE:

// Create the Chart and Line menus.

//MakeChartMenu(hwnd);
// MakeLineMenu(hwnd, hpen, hbmp);
return 0;

case WM_COMMAND:

// Test for the identifier of a command item.

switch(LOWORD(wParam))
{
case IDM_FI_OPEN:
//DoFileOpen(); // application-defined
break;

case IDM_FI_CLOSE:
//DoFileClose(); // application-defined
break;
// Process other menu commands.

default:
break;

}
return 0;
/*
// Process other window messages.
case WM_LBUTTONDOWN:
// Get the bounding rectangle of the client area.

GetClientRect(hwnd, (LPRECT) &rc);

// Get the client coordinates for the mouse click.

pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);

// If the mouse click took place inside the client
// area, execute the application-defined function
// that displays the shortcut menu.

if (PtInRect((LPRECT) &rc, pt))
HandlePopupMenu(hwnd, pt);
break;
*/

case WM_CONTEXTMENU:
if( (hmenu = LoadMenu(hinst, MAKEINTRESOURCE(PopupMenu))) == NULL )
break;

// Get a handle to the first shortcut menu
hmenuTrackPopup = GetSubMenu(hmenu, 0);

// Display the popup menu when the user right-clicks
TrackPopupMenu(hmenuTrackPopup,
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
LOWORD(lParam),
HIWORD(lParam),
0,
hwnd,
NULL);
break;
/*if (!OnContextMenu(hwnd, GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam)))
return DefWindowProc(hwnd, uMsg, wParam, lParam);
break; */

case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return NULL;
}

VOID APIENTRY HandlePopupMenu(HWND hwnd, POINT pt)
{
HMENU hmenu; // menu template
HMENU hmenuTrackPopup; // shortcut menu

// Load the menu template containing the shortcut menu from the
// application's resources.

if( (hmenu = LoadMenu(hinst, MAKEINTRESOURCE(PopupMenu))) == NULL )
//hmenu = LoadMenu(hinst, "PopupMenu");
//if (hmenu == NULL)
return;

// Get the first shortcut menu in the menu template. This is the
// menu that TrackPopupMenu displays.

hmenuTrackPopup = GetSubMenu(hmenu, 0);

// TrackPopup uses screen coordinates, so convert the
// coordinates of the mouse click to screen coordinates.

ClientToScreen(hwnd, (LPPOINT) &pt);

// Draw and track the shortcut menu.

TrackPopupMenu(hmenuTrackPopup, TPM_LEFTALIGN | TPM_LEFTBUTTON,
pt.x, pt.y, 0, hwnd, NULL);

// Destroy the menu.

DestroyMenu(hmenu);
}

BOOL WINAPI OnContextMenu(HWND hwnd, int x, int y)
{
RECT rc; // client area of window
POINT pt = { x, y }; // location of mouse click

// Get the bounding rectangle of the client area.

GetClientRect(hwnd, &rc);

// Convert the mouse position to client coordinates.

ScreenToClient(hwnd, &pt);

// If the position is in the client area, display a
// shortcut menu.

if (PtInRect(&rc, pt))
{
ClientToScreen(hwnd, &pt);
DisplayContextMenu(hwnd, pt);
return TRUE;
}

// Return FALSE if no menu is displayed.

return FALSE;
}

VOID APIENTRY DisplayContextMenu(HWND hwnd, POINT pt)
{
HMENU hmenu; // top-level menu
HMENU hmenuTrackPopup; // shortcut menu

// Load the menu resource.

if( (hmenu = LoadMenu(hinst, MAKEINTRESOURCE(PopupMenu))) == NULL )
//if ((hmenu = LoadMenu(hinst, "PopupMenu")) == NULL)
return;

// TrackPopupMenu cannot display the menu bar so get
// a handle to the first shortcut menu.

hmenuTrackPopup = GetSubMenu(hmenu, 0);

// Display the shortcut menu. Track the right mouse
// button.

TrackPopupMenu(hmenuTrackPopup,
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
pt.x, pt.y, 0, hwnd, NULL);

// Destroy the menu.

DestroyMenu(hmenu);
}

VOID MakeChartMenu(HWND hwnd)
{
HBITMAP hbmpPie; // handle to pie chart bitmap
HBITMAP hbmpLine; // handle to line chart bitmap
HBITMAP hbmpBar; // handle to bar chart bitmap
HMENU hmenuMain; // handle to main menu
HMENU hmenuChart; // handle to Chart menu

// Load the pie, line, and bar chart bitmaps from the
// resource-definition file.

hbmpPie = LoadBitmap(hinst, MAKEINTRESOURCE(PIE));
hbmpLine = LoadBitmap(hinst, MAKEINTRESOURCE(LINE));
hbmpBar = LoadBitmap(hinst, MAKEINTRESOURCE(BAR));

// Create the Chart menu and add it to the menu bar.
// Append the Pie, Line, and Bar menu items to the Chart
// menu.

hmenuMain = GetMenu(hwnd);
hmenuChart = CreatePopupMenu();
AppendMenu(hmenuMain, MF_STRING | MF_POPUP, (UINT) hmenuChart,
"Chart");
AppendMenu(hmenuChart, MF_BITMAP, IDM_PIE, (LPCTSTR) hbmpPie);
AppendMenu(hmenuChart, MF_BITMAP, IDM_LINE,
(LPCTSTR) hbmpLine);
AppendMenu(hmenuChart, MF_BITMAP, IDM_BAR, (LPCTSTR) hbmpBar);

return;
}
/*
VOID MakeLineMenu(HWND hwnd, HPEN phpen, HBITMAP phbmp)
{
HMENU hmenuLines; // handle to Lines menu
HMENU hmenu; // handle to main menu
COLORREF crMenuClr; // menu-item background color
HBRUSH hbrBackground; // handle to background brush
HBRUSH hbrOld; // handle to previous brush
WORD wLineX; // width of line bitmaps
WORD wLineY; // height of line bitmaps
HDC hdcMain; // handle to main window's DC
HDC hdcLines; // handle to compatible DC
HBITMAP hbmpOld; // handle to previous bitmap
int i; // loop counter

// Create the Lines menu. Add it to the menu bar.

hmenu = GetMenu(hwnd);
hmenuLines = CreatePopupMenu();
AppendMenu(hmenu, MF_STRING | MF_POPUP,
(UINT) hmenuLines, "&Lines");

// Create a brush for the menu-item background color.

crMenuClr = GetSysColor(COLOR_MENU);
hbrBackground = CreateSolidBrush(crMenuClr);

// Create a compatible device context for the line bitmaps,
// and then select the background brush into it.

hdcMain = GetDC(hwnd);
hdcLines = CreateCompatibleDC(hdcMain);
hbrOld = SelectObject(hdcLines, hbrBackground);

// Get the dimensions of the check-mark bitmap. The width of
// the line bitmaps will be five times the width of the
// check-mark bitmap.

wLineX = GetSystemMetrics(SM_CXMENUCHECK) * (WORD) 5;
wLineY = GetSystemMetrics(SM_CYMENUCHECK);

// Create the bitmaps and select them, one at a time, into the
// compatible device context. Initialize each bitmap by
// filling it with the menu-item background color.

for (i = 0; i < CPENS; i++)
{
phbmp[i] = CreateCompatibleBitmap(hdcMain, wLineX, wLineY);
if (i == 0)
hbmpOld = SelectObject(hdcLines, (HGDIOBJ)phbmp[i]);
else
SelectObject(hdcLines, (HGDIOBJ)phbmp[i]);
ExtFloodFill(hdcLines, 0, 0, crMenuClr, FLOODFILLBORDER);
}

// Create the pens.

phpen[0] = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
phpen[1] = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
phpen[2] = CreatePen(PS_DASH, 1, RGB(0, 0, 0));
phpen[3] = CreatePen(PS_DASHDOT, 1, RGB(0, 0, 0));
phpen[4] = CreatePen(PS_DASHDOTDOT, 1, RGB(0, 0, 0));

// Select a pen and a bitmap into the compatible device
// context, draw a line into the bitmap, and then append
// the bitmap as an item in the Lines menu.

for (i = 0; i < CPENS; i++)
{
SelectObject(hdcLines, (HGDIOBJ)phbmp[i]);
SelectObject(hdcLines, (HGDIOBJ)phpen[i]);
MoveToEx(hdcLines, 0, wLineY / 2, NULL);
LineTo(hdcLines, wLineX, wLineY / 2);
AppendMenu(hmenuLines, MF_BITMAP, i + 1,
(LPCTSTR) phbmp[i]);
}

// Release the main window's device context and destroy the
// compatible device context. Also, destroy the background
// brush.

ReleaseDC(hwnd, hdcMain);
SelectObject(hdcLines, hbrOld);
DeleteObject(hbrBackground);
SelectObject(hdcLines, hbmpOld);
DeleteDC(hdcLines);

return;
}
*/





and resource.h:


//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Win32Menu.rc
//
#define SOLID 0
#define IDM_PIE 1
#define DOT 1
#define PIE 1
#define IDM_LINE 2
#define DASH 2
#define LINE 2
#define IDM_BAR 3
#define DASHDOT 3
#define BAR 3
#define DASHDOTDOT 4
#define CPENS 5
#define IDR_MENU1 101
#define IDB_BITMAP1 102
#define IDB_BITMAP2 103
#define IDB_BITMAP3 104
#define PopupMenu 1001
#define IDM_FONT_COURIER 10001
#define IDM_FONT_TMSRMN 10002
#define IDM_FONT_SWISS 10003
#define IDM_FONT_HELV 10004
#define IDM_FONT_OLDENG 10005
#define IDM_SIZE_7 10006
#define IDM_SIZE_8 10007
#define IDM_SIZE_9 10008
#define IDM_SIZE_10 10009
#define IDM_SIZE_11 10010
#define IDM_SIZE_12 10011
#define IDM_SIZE_14 10012
#define IDM_STYLE_BOLD 10013
#define IDM_STYLE_ITALIC 10014
#define IDM_STYLE_SO 10015
#define IDM_STYLE_SUPER 10016
#define IDM_STYLE_SUB 10017
#define ID_FILE_EXIT 40001
#define ID_FILE_CLOSE40002 40002
#define IDM_FI_OPEN 40003
#define IDM_FI_CLOSE 40004

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40005
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif






and create a Win32Menu.rc:

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE
BEGIN
"resource.h\0"
END

2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END

3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END

#endif // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Menu
//

IDR_MENU1 MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open", IDM_FI_OPEN
MENUITEM "&Close", IDM_FI_CLOSE
END
END

PopupMenu MENU
BEGIN
POPUP "Dummy Popup"
BEGIN
POPUP "Fonts"
BEGIN
MENUITEM "Courier", IDM_FONT_COURIER
MENUITEM "Times Roman", IDM_FONT_TMSRMN
MENUITEM "Swiss", IDM_FONT_SWISS
MENUITEM "Helvetica", IDM_FONT_HELV
MENUITEM "Old English", IDM_FONT_OLDENG
END
POPUP "Sizes"
BEGIN
MENUITEM "7", IDM_SIZE_7
MENUITEM "8", IDM_SIZE_8
MENUITEM "9", IDM_SIZE_9
MENUITEM "10", IDM_SIZE_10
MENUITEM "11", IDM_SIZE_11
MENUITEM "12", IDM_SIZE_12
MENUITEM "14", IDM_SIZE_14
END
POPUP "Styles"
BEGIN
MENUITEM "Bold", IDM_STYLE_BOLD
MENUITEM "Italic", IDM_STYLE_ITALIC
MENUITEM "Strike Out", IDM_STYLE_SO
MENUITEM "Superscript", IDM_STYLE_SUPER
MENUITEM "Subscript", IDM_STYLE_SUB
END
END
END


/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//

IDB_BITMAP1 BITMAP "bar.bmp"
IDB_BITMAP2 BITMAP "pie.bmp"
IDB_BITMAP3 BITMAP "line.bmp"
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED





Share this post


Link to post
Share on other sites
MSDN library pre-.NET era is quite tough, even for beginner level. please start with a book since most of time they are organized in a proper way. Maybe you try Charles Petzold, it's quite expensive, though comprehensive, but any books will do.

Share this post


Link to post
Share on other sites
Quote:

Where do I specify the MENUINFO for each menu, such as to
give the file menu the static text label of "&File"?


You just need to specifiy them anywhere before you create the menu. They're just a structure, and you could keep them as local variables, class variables, etc. The one main reason to keep them local is that you can always acquire the MENUINFO later on. The only reason to keep it at a higher scope is if you plan to do a lot of editing to the menu, but there are better, and safer alternatives.

Quote:

Where/how do I define each Menu/MenuItem's ID? (e.g., IDM_FILE)


The Menu/MenuItem's ID is just an integer. Just place it in the correct scope, and everything should be fine. Just don't place it in resource.h if you're creating it programatically, as this will be overwritten by Visual Studio.

As far as CreateMenu, CreatePopupMenu, the names hopefully give it away. InsertMenu has been replaced by InsertMenuItem. You use that if you want to insert something at a specific location (in the middle of a menu, or at the menu, etc.). AppendMenu is used if you just want to place the new item at the very end.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this