|
|
Microsoft Windows NT Build 297 06-28-1992
/*************************************************************************\
*
* This sample demonstrates migrating a PM application demonstrating
* menu functionality to Win32 code. The sample demstrates Popup menus,
* cascading menus, checking/unchecking and enabling/disabling menu
* items, bitmaps as menu items, switching menus on the fly, and adding
* menu items on the fly. This sample is meant to be accompanied by
* the original PM code (MenusPM.txt) and an article (Readme.txt).
*
\*************************************************************************/
#include <windows.h>
#include "menus.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
HANDLE hInst, hAccel;
LONG APIENTRY MainWndProc (HWND, UINT, UINT, LONG);
int APIENTRY WinMain (HANDLE hInstance,
HANDLE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASS wc;
UNREFERENCED_PARAMETER( lpCmdLine );
hInst = hInstance;
/*********************************************************************\
*
* Notice wc.lpszMenuName is a symbolic constant, cast as a LPTSTR.
* This is done rather than using a string because of the way the
* Resconv.exe utility converts the resource file.
*
\*********************************************************************/
if (!hPrevInstance)
{
wc.style = CS_HREDRAW | CS_VREDRAW; // Replaces CS_SIZEREDRAW.
wc.lpfnWndProc = (WNDPROC)MainWndProc; // The client window procedure.
wc.cbClsExtra = 0; // No room reserved for extra data.
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = (LPTSTR)ID_RESOURCE;
wc.lpszClassName = "MenuClass";
RegisterClass(&wc);
};
hWnd = CreateWindow ("MenuClass",
"Menu Migration Sample", // Caption.
WS_OVERLAPPEDWINDOW, // Replaces FCF_SYSMENU,
// and FCF_MINMAX.
CW_USEDEFAULT, // These 4 replace
CW_USEDEFAULT, // FCF_SHELLPOSITION.
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, // No parents.
NULL, // Use the window class menu.
hInstance, // Owner.
NULL); // No pointer.
ShowWindow (hWnd, nCmdShow); // Show the window.
UpdateWindow (hWnd); // Paint the window.
/**********************************************************************\
*
* In Windows to use an accelerator table, you must load it and then
* use TranslateAccelerator in the message loop. Note again the use
* of the LPTSTR cast #define'd value due to the way the resconv.exe
* converts the resource file.
*
\**********************************************************************/
hAccel = LoadAccelerators (hInst, (LPTSTR)ID_RESOURCE);
while (GetMessage (&msg, NULL, NULL, NULL))
{
if (!TranslateAccelerator (hWnd, hAccel, &msg))
{
TranslateMessage (&msg); // Translate virtual key codes.
DispatchMessage (&msg); // Dispatch message to window.
}
}
return (msg.wParam); // Returns value from PostQuitMessage.
}
LONG APIENTRY MainWndProc (HWND hwnd,
UINT message,
UINT wParam,
LONG lParam)
{
/**********************************************************************\
*
* I've left the following PM definition in just as a reference so that
* the converted code can be followed more easily.
*
* // Used in switching menus.
* static HWND hwndFrame; // Handle to the window frame.
* static HWND hwndMenu; // Handle to the original menu.
* static HWND hwndMenuAlt; // Handle to the switched to menu.
*
* // Used in the popup menu.
* static HWND hwndMenuPopup; // Handle to the popup menu.
* HPS hps; // These 3 variables are used in
* RECTL rcl; // in locating the popup menu.
* POINTL ptlMouse ;
*
* // Used in enable/disable and checking menu items.
* SHORT sState; // Used to toggle 'checked' and
* // 'enabled' menu item state.
*
* // Used in adding menu items on the fly.
* HWND hSubMenu; // Handle to added menu item.
* MENUITEM mi; // Structure for new menu item.
* static USHORT ActionBarID = 1000; // Used to ID new menu item.
* static USHORT SubMenuID = 6000; // Used to ID new sub menu item.
* CHAR buffer[10]; // Holds string for menu item.
* MENUCREATETEMPLATE mt; // See type definition in menus.h
*
\**********************************************************************/
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
HMENU hMenu, hMenuAdd, hPopupMenu, hTrackPopupMenu;
static HMENU hwndMenu, hwndMenuAlt;
HBITMAP Tool1, Tool2, Tool3, Tool4, Tool5, Tool6, Logo;
POINT point;
static INT SubMenuID=6000, ActionBarID=1000;
char buffer[10];
switch (message)
{
case WM_CREATE:
/************************************************************\
*
* // Loading the popup menu.
* hwndMenuPopup = WinLoadMenu (hwnd, 0, ID_POPUP) ;
* WinSetWindowPos (hwndMenuPopup, NULL,
* 0, 0, 0, 0, SWP_SIZE) ;
* WinSetParent (hwndMenuPopup, HWND_DESKTOP, FALSE) ;
*
* hwndFrame = WinQueryWindow(hwnd, QW_PARENT,FALSE);
* hwndMenu = WinWindowFromID (hwndFrame, FID_MENU);
* WinSetParent(hwndMenu, HWND_OBJECT, TRUE);
* hwndMenuAlt = WinLoadMenu( hwndFrame, 0, ID_ALTERNATE);
* WinSetParent(hwndMenuAlt, HWND_OBJECT, TRUE);
* WinSetParent(hwndMenu, hwndFrame, TRUE);
* return 0;
*
* In PM, to make one menu disappear and to make another
* appear in its place, it's a simple matter setting the
* parent of the first menu to be HWND_OBJECT, and the
* second menu's parent then becomes the window frame.
* This also allows you to maintain the state of a menu
* when you switch back and forth. In Windows, it's even
* simpler: you just use SetMenu() on the window handle
* setting the menu to NULL, and then make the call again
* setting it to the desired alternate menu. To switch
* back and forth you save the menu handles and use them
* alternately. See IDM_SWITCH and IDM_ALT_SWITCH.
*
* The PM code was a little more complicated because the
* WinLoadMenu call requires a handle to a frame window.
* Below the Windows code was a bit simpler to get the
* handles to the menus.
*
\************************************************************/
hwndMenuAlt = LoadMenu(hInst, (LPSTR)ID_ALTERNATE);
hwndMenu = GetMenu(hwnd);
/************************************************************\
*
* Because Windows doesn't support bitmaps being defined in
* menu within the .rc file, you must build them on the fly
* using AppendMenu() or InsertMenu() etc. Here the bitmaps
* are loaded, and appended to a menu, and finally that menu
* is inserted into place on the action bar.
*
\************************************************************/
hMenu = CreateMenu();
Tool1 = LoadBitmap(hInst, "Tool1");
AppendMenu (hMenu, MF_BITMAP, IDM_TOOL1, Tool1);
AppendMenu (hMenu, MF_SEPARATOR, 0,0);
Tool3 = LoadBitmap(hInst, "Tool3");
AppendMenu (hMenu, MF_BITMAP, IDM_TOOL3, Tool3);
AppendMenu (hMenu, MF_SEPARATOR, 0,0);
Tool5 = LoadBitmap(hInst, "Tool5");
AppendMenu (hMenu, MF_BITMAP, IDM_TOOL5, Tool5);
Tool2 = LoadBitmap(hInst, "Tool2");
AppendMenu (hMenu, MF_MENUBARBREAK | MF_BITMAP, IDM_TOOL2, Tool2);
AppendMenu (hMenu, MF_SEPARATOR, 0,0);
Tool4 = LoadBitmap(hInst, "Tool4");
AppendMenu (hMenu, MF_BITMAP, IDM_TOOL4, Tool4);
AppendMenu (hMenu, MF_SEPARATOR, 0,0);
Tool6 = LoadBitmap(hInst, "Tool6");
AppendMenu (hMenu, MF_BITMAP, IDM_TOOL6, Tool6);
hwndMenu = GetMenu(hwnd);
Logo = LoadBitmap(hInst, "Logo");
InsertMenu (hwndMenu, 1, MF_BITMAP | MF_BYPOSITION | MF_POPUP,
(DWORD)hMenu, Logo);
DrawMenuBar(hwnd);
return (0);
case WM_PAINT :
hdc = BeginPaint (hwnd, (LPPAINTSTRUCT)&ps);
GetClientRect (hwnd, (LPRECT)&rect);
FillRect(hdc, (LPRECT)&rect, GetStockObject (WHITE_BRUSH));
EndPaint (hwnd, (LPPAINTSTRUCT)&ps);
return (0);
case WM_RBUTTONUP:
/*************************************************************\
*
* WinQueryPointerPos (HWND_DESKTOP, &ptlMouse) ;
* ptlMouse.y += WinQuerySysValue (HWND_DESKTOP, SV_CYMENU) ;
* WinSetWindowPos (hwndMenuPopup, HWND_TOP,
* (SHORT) ptlMouse.x, (SHORT) ptlMouse.y,
* 0, 0, SWP_MOVE | SWP_SHOW) ;
* WinSendMsg (hwndMenuPopup, MM_SELECTITEM,
* MPFROM2SHORT (IDM_POPUP, FALSE),
* MPFROMSHORT (FALSE)) ;
* WinSetCapture (HWND_DESKTOP, hwndMenuPopup) ;
* return 0 ;
*
* Replacing the Popup Menu Code.
*
\*************************************************************/
hPopupMenu = LoadMenu (hInst, "ID_Popup");
hTrackPopupMenu = GetSubMenu( hPopupMenu, 0);
point.x = (LONG)LOWORD(lParam);
point.y = (LONG)HIWORD(lParam);
ClientToScreen(hwnd, (LPPOINT)&point);
SetCapture(hTrackPopupMenu);
TrackPopupMenu(hTrackPopupMenu, TPM_LEFTALIGN,
point.x, point.y, 0, hwnd, NULL);
DestroyMenu(hPopupMenu);
return (0);
case WM_DESTROY :
PostQuitMessage (0);
return (0);
case WM_COMMAND:
// LOWORD added for portability
switch (LOWORD(wParam))
{
case -1:
return (0);
case IDM_ALT_ADD:
/************************************************************\
*
* // Filling out the menu template, using many defaults.
* mt.size = 0;
* mt.version = 0;
* mt.codepage = 0;
* mt.mnemonic = 0;
* mt.itemcount = 1;
* mt.item[0].afStyle = MIS_TEXT;
* mt.item[0].afAttribute = 0;
* mt.item[0].id = SubMenuID;
* strcpy(mt.item[0].text,
* itoa(SubMenuID++,buffer,10));
*
* // Create a popup menu using template information.
* hSubMenu = WinCreateMenu( hwndMenuAlt, &mt);
*
* // Filling out the MENUITEM structure.
* mi.iPosition = MIT_END;
* mi.afStyle = MIS_TEXT | MIS_SUBMENU;
* mi.afAttribute = 0;
* mi.id = ActionBarID;
* mi.hwndSubMenu = hSubMenu;
* mi.hItem = 0;
*
* // Inserting the new item.
* WinSendMsg(hwndMenuAlt,MM_INSERTITEM,(MPARAM)&mi,
* (MPARAM)(PCH)itoa(ActionBarID++,buffer,10));
* break;
*
* To add menu items on the fly (from an application during
* runtime), you fill out a menu item structure, and then
* insert it. In Windows, the structure is given to you
* with CreateMenu(), and you fill it in with AppendMenu()
* and InsertMenu().
*
\************************************************************/
hMenuAdd = CreateMenu();
AppendMenu (hMenuAdd, MF_STRING, SubMenuID++,
itoa(SubMenuID++, buffer, 10));
hwndMenuAlt = GetMenu(hwnd);
InsertMenu (hwndMenuAlt, (UINT)-1,
MF_STRING | MF_BYPOSITION | MF_POPUP,
(DWORD)hMenuAdd, itoa(ActionBarID++, buffer, 10));
DrawMenuBar(hwnd);
return (0);
case IDM_SWITCH:
/************************************************************\
*
* WinSetParent(hwndMenu, HWND_OBJECT, TRUE);
* WinSetParent(hwndMenuAlt, hwndFrame, TRUE);
* WinPostMsg (hwndFrame, WM_UPDATEFRAME,
* MPFROMSHORT(FCF_MENU), 0L);
* break;
*
* As mentioned under the WM_CREATE, to switch menus during
* runtime under PM, you change the menu's parent: the one
* you want to disappear to HWND_OBJECT, the one you want
* to appear to the window frame. In Windows the concept
* is to change the menu belonging to the window. You can
* set the menu to NULL to make a menu disappear, and you
* can set it to an alternate menu to make a different one
* appear. The following two case statements show this.
*
\************************************************************/
SetMenu(hwnd,NULL);
SetMenu(hwnd, hwndMenuAlt);
return (0);
case IDM_ALT_SWITCH:
SetMenu(hwnd, NULL);
SetMenu(hwnd, hwndMenu);
return (0);
case IDM_HELP:
/************************************************************\
*
* The PM code showed how you could replace the WM_COMMAND
* message sent with the Help option with a special WM_HELP,
* this isn't supported under Windows. So the case for
* help must be placed within the WM_COMMAND switch statment.
*
\************************************************************/
MessageBox (hwnd, "Help Message Box",
"Win32 Menus Code",
MB_OK | MB_ICONASTERISK);
return (0);
case IDM_DISABLE:
/************************************************************\
*
*
* // Toggling the check on "Disable Cascade".
* (MRESULT)sState = WinSendMsg( hwndMenu,
* MM_QUERYITEMATTR,
* MPFROM2SHORT(IDM_DISABLE, TRUE),
* MPFROMSHORT(MIA_CHECKED));
*
* sState ^= MIA_CHECKED;
*
* WinSendMsg(hwndMenu,
* MM_SETITEMATTR,
* MPFROM2SHORT(IDM_DISABLE, TRUE),
* MPFROM2SHORT(MIA_CHECKED, sState));
*
*
* // Toggling the enable for "Cascade".
* (MRESULT)sState = WinSendMsg( hwndMenu,
* MM_QUERYITEMATTR,
* MPFROM2SHORT(IDM_SUB3, TRUE),
* MPFROMSHORT(MIA_DISABLED));
*
* sState ^= MIA_DISABLED;
*
* WinSendMsg(hwndMenu,
* MM_SETITEMATTR,
* MPFROM2SHORT(IDM_SUB3, TRUE),
* MPFROM2SHORT(MIA_DISABLED, sState));
* break;
*
* The above PM code and the following Windows code show how
* to toggle a check the "Disable Cascade" menu item, and
* how to toggle an "enable" on the "Cascade" menu item. If
* you find the PM code a bit difficult to follow, you can
* look at the comments in the original PM code [deleted
* here].
*
\************************************************************/
if(CheckMenuItem(hwndMenu, IDM_DISABLE, MF_CHECKED)==MF_CHECKED)
{
CheckMenuItem(hwndMenu, IDM_DISABLE, MF_UNCHECKED);
EnableMenuItem(GetSubMenu(hwndMenu,0),2,
MF_ENABLED|MF_BYPOSITION);
}
else
EnableMenuItem(GetSubMenu(hwndMenu,0),2,
MF_GRAYED|MF_BYPOSITION);
return (0);
default:
MessageBeep(0);
MessageBox( hwnd, "This item has no functionality.",
"Win32 Menus Code",
MB_APPLMODAL | MB_ICONINFORMATION | MB_OK);
return (0);
}
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.