|
|
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.