Annotation of q_a/samples/menus/menus.c, revision 1.1.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.