File:  [WindowsNT SDKs] / q_a / samples / menus / menus.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:29:19 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntsdk-oct-1992, ntsdk-jun-1992, HEAD
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);
}

unix.superglobalmegacorp.com

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