|
|
1.1 root 1: /*************************************************************************\
2: *
3: * This sample demonstrates migrating a PM application demonstrating
4: * menu functionality to Win32 code. The sample demstrates Popup menus,
5: * cascading menus, checking/unchecking and enabling/disabling menu
6: * items, bitmaps as menu items, switching menus on the fly, and adding
7: * menu items on the fly. This sample is meant to be accompanied by
8: * the original PM code (MenusPM.txt) and an article (Readme.txt).
9: *
10: \*************************************************************************/
11:
12: #include <windows.h>
13: #include "menus.h"
14:
15: #include "string.h"
16: #include "stdio.h"
17: #include "stdlib.h"
18:
19: HANDLE hInst, hAccel;
20:
21:
22: LONG APIENTRY MainWndProc (HWND, UINT, UINT, LONG);
23:
24: int APIENTRY WinMain (HANDLE hInstance,
25: HANDLE hPrevInstance,
26: LPSTR lpCmdLine,
27: int nCmdShow)
28:
29:
30: {
31:
32: MSG msg;
33: HWND hWnd;
34: WNDCLASS wc;
35:
36:
37:
38: UNREFERENCED_PARAMETER( lpCmdLine );
39:
40: hInst = hInstance;
41:
42: /*********************************************************************\
43: *
44: * Notice wc.lpszMenuName is a symbolic constant, cast as a LPTSTR.
45: * This is done rather than using a string because of the way the
46: * Resconv.exe utility converts the resource file.
47: *
48: \*********************************************************************/
49:
50: if (!hPrevInstance)
51: {
52: wc.style = CS_HREDRAW | CS_VREDRAW; // Replaces CS_SIZEREDRAW.
53: wc.lpfnWndProc = (WNDPROC)MainWndProc; // The client window procedure.
54: wc.cbClsExtra = 0; // No room reserved for extra data.
55: wc.cbWndExtra = 0;
56: wc.hInstance = hInstance;
57: wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
58: wc.hCursor = LoadCursor (NULL, IDC_ARROW);
59: wc.hbrBackground = GetStockObject (WHITE_BRUSH);
60: wc.lpszMenuName = (LPTSTR)ID_RESOURCE;
61: wc.lpszClassName = "MenuClass";
62:
63: RegisterClass(&wc);
64: };
65:
66:
67: hWnd = CreateWindow ("MenuClass",
68: "Menu Migration Sample", // Caption.
69: WS_OVERLAPPEDWINDOW, // Replaces FCF_SYSMENU,
70: // and FCF_MINMAX.
71: CW_USEDEFAULT, // These 4 replace
72: CW_USEDEFAULT, // FCF_SHELLPOSITION.
73: CW_USEDEFAULT,
74: CW_USEDEFAULT,
75: NULL, // No parents.
76: NULL, // Use the window class menu.
77: hInstance, // Owner.
78: NULL); // No pointer.
79:
80: ShowWindow (hWnd, nCmdShow); // Show the window.
81: UpdateWindow (hWnd); // Paint the window.
82:
83: /**********************************************************************\
84: *
85: * In Windows to use an accelerator table, you must load it and then
86: * use TranslateAccelerator in the message loop. Note again the use
87: * of the LPTSTR cast #define'd value due to the way the resconv.exe
88: * converts the resource file.
89: *
90: \**********************************************************************/
91:
92: hAccel = LoadAccelerators (hInst, (LPTSTR)ID_RESOURCE);
93:
94: while (GetMessage (&msg, NULL, NULL, NULL))
95: {
96: if (!TranslateAccelerator (hWnd, hAccel, &msg))
97: {
98: TranslateMessage (&msg); // Translate virtual key codes.
99: DispatchMessage (&msg); // Dispatch message to window.
100: }
101: }
102:
103: return (msg.wParam); // Returns value from PostQuitMessage.
104:
105: }
106:
107: LONG APIENTRY MainWndProc (HWND hwnd,
108: UINT message,
109: UINT wParam,
110: LONG lParam)
111:
112: {
113:
114: /**********************************************************************\
115: *
116: * I've left the following PM definition in just as a reference so that
117: * the converted code can be followed more easily.
118: *
119: * // Used in switching menus.
120: * static HWND hwndFrame; // Handle to the window frame.
121: * static HWND hwndMenu; // Handle to the original menu.
122: * static HWND hwndMenuAlt; // Handle to the switched to menu.
123: *
124: * // Used in the popup menu.
125: * static HWND hwndMenuPopup; // Handle to the popup menu.
126: * HPS hps; // These 3 variables are used in
127: * RECTL rcl; // in locating the popup menu.
128: * POINTL ptlMouse ;
129: *
130: * // Used in enable/disable and checking menu items.
131: * SHORT sState; // Used to toggle 'checked' and
132: * // 'enabled' menu item state.
133: *
134: * // Used in adding menu items on the fly.
135: * HWND hSubMenu; // Handle to added menu item.
136: * MENUITEM mi; // Structure for new menu item.
137: * static USHORT ActionBarID = 1000; // Used to ID new menu item.
138: * static USHORT SubMenuID = 6000; // Used to ID new sub menu item.
139: * CHAR buffer[10]; // Holds string for menu item.
140: * MENUCREATETEMPLATE mt; // See type definition in menus.h
141: *
142: \**********************************************************************/
143:
144: HDC hdc;
145: PAINTSTRUCT ps;
146: RECT rect;
147:
148:
149: HMENU hMenu, hMenuAdd, hPopupMenu, hTrackPopupMenu;
150: static HMENU hwndMenu, hwndMenuAlt;
151:
152: HBITMAP Tool1, Tool2, Tool3, Tool4, Tool5, Tool6, Logo;
153:
154: POINT point;
155:
156: static INT SubMenuID=6000, ActionBarID=1000;
157:
158: char buffer[10];
159:
160: switch (message)
161: {
162: case WM_CREATE:
163:
164: /************************************************************\
165: *
166: * // Loading the popup menu.
167: * hwndMenuPopup = WinLoadMenu (hwnd, 0, ID_POPUP) ;
168: * WinSetWindowPos (hwndMenuPopup, NULL,
169: * 0, 0, 0, 0, SWP_SIZE) ;
170: * WinSetParent (hwndMenuPopup, HWND_DESKTOP, FALSE) ;
171: *
172: * hwndFrame = WinQueryWindow(hwnd, QW_PARENT,FALSE);
173: * hwndMenu = WinWindowFromID (hwndFrame, FID_MENU);
174: * WinSetParent(hwndMenu, HWND_OBJECT, TRUE);
175: * hwndMenuAlt = WinLoadMenu( hwndFrame, 0, ID_ALTERNATE);
176: * WinSetParent(hwndMenuAlt, HWND_OBJECT, TRUE);
177: * WinSetParent(hwndMenu, hwndFrame, TRUE);
178: * return 0;
179: *
180: * In PM, to make one menu disappear and to make another
181: * appear in its place, it's a simple matter setting the
182: * parent of the first menu to be HWND_OBJECT, and the
183: * second menu's parent then becomes the window frame.
184: * This also allows you to maintain the state of a menu
185: * when you switch back and forth. In Windows, it's even
186: * simpler: you just use SetMenu() on the window handle
187: * setting the menu to NULL, and then make the call again
188: * setting it to the desired alternate menu. To switch
189: * back and forth you save the menu handles and use them
190: * alternately. See IDM_SWITCH and IDM_ALT_SWITCH.
191: *
192: * The PM code was a little more complicated because the
193: * WinLoadMenu call requires a handle to a frame window.
194: * Below the Windows code was a bit simpler to get the
195: * handles to the menus.
196: *
197: \************************************************************/
198:
199: hwndMenuAlt = LoadMenu(hInst, (LPSTR)ID_ALTERNATE);
200: hwndMenu = GetMenu(hwnd);
201:
202:
203: /************************************************************\
204: *
205: * Because Windows doesn't support bitmaps being defined in
206: * menu within the .rc file, you must build them on the fly
207: * using AppendMenu() or InsertMenu() etc. Here the bitmaps
208: * are loaded, and appended to a menu, and finally that menu
209: * is inserted into place on the action bar.
210: *
211: \************************************************************/
212:
213: hMenu = CreateMenu();
214:
215: Tool1 = LoadBitmap(hInst, "Tool1");
216: AppendMenu (hMenu, MF_BITMAP, IDM_TOOL1, Tool1);
217: AppendMenu (hMenu, MF_SEPARATOR, 0,0);
218: Tool3 = LoadBitmap(hInst, "Tool3");
219: AppendMenu (hMenu, MF_BITMAP, IDM_TOOL3, Tool3);
220: AppendMenu (hMenu, MF_SEPARATOR, 0,0);
221: Tool5 = LoadBitmap(hInst, "Tool5");
222: AppendMenu (hMenu, MF_BITMAP, IDM_TOOL5, Tool5);
223:
224: Tool2 = LoadBitmap(hInst, "Tool2");
225: AppendMenu (hMenu, MF_MENUBARBREAK | MF_BITMAP, IDM_TOOL2, Tool2);
226: AppendMenu (hMenu, MF_SEPARATOR, 0,0);
227: Tool4 = LoadBitmap(hInst, "Tool4");
228: AppendMenu (hMenu, MF_BITMAP, IDM_TOOL4, Tool4);
229: AppendMenu (hMenu, MF_SEPARATOR, 0,0);
230: Tool6 = LoadBitmap(hInst, "Tool6");
231: AppendMenu (hMenu, MF_BITMAP, IDM_TOOL6, Tool6);
232:
233: hwndMenu = GetMenu(hwnd);
234: Logo = LoadBitmap(hInst, "Logo");
235: InsertMenu (hwndMenu, 1, MF_BITMAP | MF_BYPOSITION | MF_POPUP,
236: (DWORD)hMenu, Logo);
237: DrawMenuBar(hwnd);
238:
239: return (0);
240:
241:
242: case WM_PAINT :
243: hdc = BeginPaint (hwnd, (LPPAINTSTRUCT)&ps);
244: GetClientRect (hwnd, (LPRECT)&rect);
245: FillRect(hdc, (LPRECT)&rect, GetStockObject (WHITE_BRUSH));
246: EndPaint (hwnd, (LPPAINTSTRUCT)&ps);
247: return (0);
248:
249:
250: case WM_RBUTTONUP:
251:
252: /*************************************************************\
253: *
254: * WinQueryPointerPos (HWND_DESKTOP, &ptlMouse) ;
255: * ptlMouse.y += WinQuerySysValue (HWND_DESKTOP, SV_CYMENU) ;
256: * WinSetWindowPos (hwndMenuPopup, HWND_TOP,
257: * (SHORT) ptlMouse.x, (SHORT) ptlMouse.y,
258: * 0, 0, SWP_MOVE | SWP_SHOW) ;
259: * WinSendMsg (hwndMenuPopup, MM_SELECTITEM,
260: * MPFROM2SHORT (IDM_POPUP, FALSE),
261: * MPFROMSHORT (FALSE)) ;
262: * WinSetCapture (HWND_DESKTOP, hwndMenuPopup) ;
263: * return 0 ;
264: *
265: * Replacing the Popup Menu Code.
266: *
267: \*************************************************************/
268:
269: hPopupMenu = LoadMenu (hInst, "ID_Popup");
270: hTrackPopupMenu = GetSubMenu( hPopupMenu, 0);
271:
272: point.x = (LONG)LOWORD(lParam);
273: point.y = (LONG)HIWORD(lParam);
274: ClientToScreen(hwnd, (LPPOINT)&point);
275: SetCapture(hTrackPopupMenu);
276: TrackPopupMenu(hTrackPopupMenu, TPM_LEFTALIGN,
277: point.x, point.y, 0, hwnd, NULL);
278: DestroyMenu(hPopupMenu);
279: return (0);
280:
281:
282: case WM_DESTROY :
283: PostQuitMessage (0);
284: return (0);
285:
286: case WM_COMMAND:
287:
288: // LOWORD added for portability
289: switch (LOWORD(wParam))
290: {
291: case -1:
292: return (0);
293:
294: case IDM_ALT_ADD:
295:
296: /************************************************************\
297: *
298: * // Filling out the menu template, using many defaults.
299: * mt.size = 0;
300: * mt.version = 0;
301: * mt.codepage = 0;
302: * mt.mnemonic = 0;
303: * mt.itemcount = 1;
304: * mt.item[0].afStyle = MIS_TEXT;
305: * mt.item[0].afAttribute = 0;
306: * mt.item[0].id = SubMenuID;
307: * strcpy(mt.item[0].text,
308: * itoa(SubMenuID++,buffer,10));
309: *
310: * // Create a popup menu using template information.
311: * hSubMenu = WinCreateMenu( hwndMenuAlt, &mt);
312: *
313: * // Filling out the MENUITEM structure.
314: * mi.iPosition = MIT_END;
315: * mi.afStyle = MIS_TEXT | MIS_SUBMENU;
316: * mi.afAttribute = 0;
317: * mi.id = ActionBarID;
318: * mi.hwndSubMenu = hSubMenu;
319: * mi.hItem = 0;
320: *
321: * // Inserting the new item.
322: * WinSendMsg(hwndMenuAlt,MM_INSERTITEM,(MPARAM)&mi,
323: * (MPARAM)(PCH)itoa(ActionBarID++,buffer,10));
324: * break;
325: *
326: * To add menu items on the fly (from an application during
327: * runtime), you fill out a menu item structure, and then
328: * insert it. In Windows, the structure is given to you
329: * with CreateMenu(), and you fill it in with AppendMenu()
330: * and InsertMenu().
331: *
332: \************************************************************/
333:
334: hMenuAdd = CreateMenu();
335: AppendMenu (hMenuAdd, MF_STRING, SubMenuID++,
336: itoa(SubMenuID++, buffer, 10));
337:
338: hwndMenuAlt = GetMenu(hwnd);
339: InsertMenu (hwndMenuAlt, (UINT)-1,
340: MF_STRING | MF_BYPOSITION | MF_POPUP,
341: (DWORD)hMenuAdd, itoa(ActionBarID++, buffer, 10));
342: DrawMenuBar(hwnd);
343: return (0);
344:
345:
346: case IDM_SWITCH:
347:
348: /************************************************************\
349: *
350: * WinSetParent(hwndMenu, HWND_OBJECT, TRUE);
351: * WinSetParent(hwndMenuAlt, hwndFrame, TRUE);
352: * WinPostMsg (hwndFrame, WM_UPDATEFRAME,
353: * MPFROMSHORT(FCF_MENU), 0L);
354: * break;
355: *
356: * As mentioned under the WM_CREATE, to switch menus during
357: * runtime under PM, you change the menu's parent: the one
358: * you want to disappear to HWND_OBJECT, the one you want
359: * to appear to the window frame. In Windows the concept
360: * is to change the menu belonging to the window. You can
361: * set the menu to NULL to make a menu disappear, and you
362: * can set it to an alternate menu to make a different one
363: * appear. The following two case statements show this.
364: *
365: \************************************************************/
366:
367: SetMenu(hwnd,NULL);
368: SetMenu(hwnd, hwndMenuAlt);
369: return (0);
370:
371: case IDM_ALT_SWITCH:
372:
373: SetMenu(hwnd, NULL);
374: SetMenu(hwnd, hwndMenu);
375: return (0);
376:
377:
378:
379: case IDM_HELP:
380:
381: /************************************************************\
382: *
383: * The PM code showed how you could replace the WM_COMMAND
384: * message sent with the Help option with a special WM_HELP,
385: * this isn't supported under Windows. So the case for
386: * help must be placed within the WM_COMMAND switch statment.
387: *
388: \************************************************************/
389: MessageBox (hwnd, "Help Message Box",
390: "Win32 Menus Code",
391: MB_OK | MB_ICONASTERISK);
392: return (0);
393:
394: case IDM_DISABLE:
395: /************************************************************\
396: *
397: *
398: * // Toggling the check on "Disable Cascade".
399: * (MRESULT)sState = WinSendMsg( hwndMenu,
400: * MM_QUERYITEMATTR,
401: * MPFROM2SHORT(IDM_DISABLE, TRUE),
402: * MPFROMSHORT(MIA_CHECKED));
403: *
404: * sState ^= MIA_CHECKED;
405: *
406: * WinSendMsg(hwndMenu,
407: * MM_SETITEMATTR,
408: * MPFROM2SHORT(IDM_DISABLE, TRUE),
409: * MPFROM2SHORT(MIA_CHECKED, sState));
410: *
411: *
412: * // Toggling the enable for "Cascade".
413: * (MRESULT)sState = WinSendMsg( hwndMenu,
414: * MM_QUERYITEMATTR,
415: * MPFROM2SHORT(IDM_SUB3, TRUE),
416: * MPFROMSHORT(MIA_DISABLED));
417: *
418: * sState ^= MIA_DISABLED;
419: *
420: * WinSendMsg(hwndMenu,
421: * MM_SETITEMATTR,
422: * MPFROM2SHORT(IDM_SUB3, TRUE),
423: * MPFROM2SHORT(MIA_DISABLED, sState));
424: * break;
425: *
426: * The above PM code and the following Windows code show how
427: * to toggle a check the "Disable Cascade" menu item, and
428: * how to toggle an "enable" on the "Cascade" menu item. If
429: * you find the PM code a bit difficult to follow, you can
430: * look at the comments in the original PM code [deleted
431: * here].
432: *
433: \************************************************************/
434:
435: if(CheckMenuItem(hwndMenu, IDM_DISABLE, MF_CHECKED)==MF_CHECKED)
436: {
437: CheckMenuItem(hwndMenu, IDM_DISABLE, MF_UNCHECKED);
438: EnableMenuItem(GetSubMenu(hwndMenu,0),2,
439: MF_ENABLED|MF_BYPOSITION);
440: }
441: else
442: EnableMenuItem(GetSubMenu(hwndMenu,0),2,
443: MF_GRAYED|MF_BYPOSITION);
444:
445: return (0);
446:
447:
448: default:
449:
450: MessageBeep(0);
451: MessageBox( hwnd, "This item has no functionality.",
452: "Win32 Menus Code",
453: MB_APPLMODAL | MB_ICONINFORMATION | MB_OK);
454: return (0);
455: }
456:
457: }
458: return DefWindowProc (hwnd, message, wParam, lParam);
459: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.