Annotation of q_a/samples/menus/menus.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.