Bootstrap

《Windows API每日一练》9.25 系统菜单

/*------------------------------------------------------------------------

 060 WIN32 API 每日一练

     第60个例子POORMENU.C:使用系统菜单

     GetSystemMenu函数

     AppendMenu函数    

 (c) www.bcdaren.com 编程达人

-----------------------------------------------------------------------*/

#include <windows.h>

#define IDM_SYS_ABOUT    1

#define IDM_SYS_HELP     2

#define IDM_SYS_REMOVE   3

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static TCHAR szAppName[] = TEXT("PoorMenu");

int WINAPI WinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,

_In_ LPSTR lpCmdLine, _In_ int nShowCmd )

{

     HMENU hMenu;

     HWND hwnd;

     MSG msg;

     WNDCLASS wndclass;

     //窗口类结构初始化

     wndclass.style           = CS_HREDRAW | CS_VREDRAW;

     wndclass.lpfnWndProc     = WndProc;

     wndclass.cbClsExtra      = 0;

     wndclass.cbWndExtra      = 0;

     wndclass.hInstance       = hInstance;

     wndclass.hCursor         = LoadCursor(NULL,IDC_ARROW);

     wndclass.hIcon           = LoadIcon(NULL,IDI_APPLICATION);

     wndclass.hbrBackground   = (HBRUSH)GetStockObject(WHITE_BRUSH);

     wndclass.lpszMenuName    = NULL;

     wndclass.lpszClassName   = szAppName;

     //注册窗口类

     if (!RegisterClass(&wndclass))

     {

          MessageBox(NULL,TEXT("This program require Windows NT!"),

                    szAppName,MB_ICONERROR);

          return 0;

     }

     //创建窗口

     hwnd = CreateWindow(szAppName,TEXT("The Poor_Person`s Menu"),

                    WS_OVERLAPPEDWINDOW,

                    CW_USEDEFAULT,CW_USEDEFAULT,

                    CW_USEDEFAULT,CW_USEDEFAULT,

                    NULL,NULL,hInstance,NULL);

     hMenu = GetSystemMenu(hwnd,FALSE);//获取系统菜单句柄副本,TRUE恢复默认值

    

     AppendMenu(hMenu,MF_SEPARATOR,0,NULL);

     AppendMenu(hMenu,MF_STRING,IDM_SYS_ABOUT,TEXT("ABOUT..."));

     AppendMenu(hMenu,MF_STRING,IDM_SYS_HELP,TEXT("HELP..."));

     AppendMenu(hMenu,MF_STRING,IDM_SYS_REMOVE,TEXT("REMOVE..."));

     ShowWindow(hwnd,nShowCmd);

     UpdateWindow(hwnd);

     while (GetMessage(&msg,NULL,0,0))

     {

          TranslateMessage(&msg);

          DispatchMessage(&msg);

     }

     return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)

{

     switch (message)

     {

     case WM_SYSCOMMAND:

          switch (LOWORD(wparam))

          {

          case IDM_SYS_ABOUT:

               MessageBox(hwnd,TEXT("A Poor-Person`s Menu Program\n")

                         TEXT("(C)www.bcdaren.com 编程达人

"),szAppName,MB_ICONINFORMATION);

              return 0;

    

          case IDM_SYS_HELP:

               MessageBox(hwnd,TEXT("Help not yet implemented!"),

                         szAppName,MB_ICONEXCLAMATION);

               return 0;

          case IDM_SYS_REMOVE:

               GetSystemMenu(hwnd,TRUE);//使上一个窗口菜单失效

               return 0;

          }

          break;

     case WM_DESTROY:

          PostQuitMessage(0);

          return 0;

     }

     return DefWindowProc(hwnd,message,wparam,lparam);

}

/******************************************************************************

_in 输入参数

_out 输出参数

_opt 参数是可选的,就是可以为NULL

_ecount 所指向的缓存的元素个素也就是括号里的数字

这些宏都被定义为空,只是让程序更容易理解!

*******************************************************************************

GetSystemMenu函数:使应用程序能够访问窗口菜单(也称为系统菜单或控制菜单)以进行复制和修改

如果此参数为FALSE,则GetSystemMenu返回当前使用的窗口菜单副本的句柄。该副本最初与窗口菜单相同,但可以修改。

如果此参数为TRUE,则GetSystemMenu会将窗口菜单重置为默认状态。上一个窗口菜单(如果有)被破坏。

HMENU GetSystemMenu(

  HWND hWnd,   //拥有窗口菜单副本的窗口句柄

  BOOL bRevert

);

*******************************************************************************

AppendMenu函数:将新项目追加到指定菜单栏,下拉菜单,子菜单或快捷菜单的末尾。您可以使用此功能来指定菜单项的内容,外观和行为

BOOL AppendMenuA(

  HMENU    hMenu,   //菜单句柄

  UINT     uFlags,  //控制新菜单项的外观和行为。

  UINT_PTR uIDNewItem,   //新菜单项的标识符,或者,如果uFlags参数设置为MF_POPUP,则为下拉菜单或子菜单的句柄

  LPCSTR   lpNewItem     //新菜单项的内容

);

*/

       运行结果:

图9-14 使用系统菜单

 

总结

实例POORMENU.C并没有添加菜单资源,而是直接将菜单添加到了系统菜单中。

首先定义了3个菜单项ID:

#define IDM_SYS_ABOUT    1

#define IDM_SYS_HELP     2

#define IDM_SYS_REMOVE   3

然后在主程序中调用GetSystemMenu函数,获取系统菜单句柄的副本。

hMenu = GetSystemMenu(hwnd,FALSE);//获取系统菜单句柄副本,TRUE恢复默认值

接着4次调用AppendMenu函数,在系统菜单内添加包括分隔符在内的4个菜单。

实例的窗口过程拦截系统菜单消息WM_SYSCOMMAND,分别根据菜单ID处理"ABOUT..."、"HELP..."和"REMOVE..."菜单。其中"REMOVE..."菜单调用GetSystemMenu函数去除新添加的系统菜单项。

GetSystemMenu(hwnd,TRUE);//使上一个窗口菜单失效

9.2.6 第61练:没有弹出菜单的多层顶级菜单

/*------------------------------------------------------------------------

 061 WIN32 API 每日一练

     第61个例子NOPOPUPS.C:没有弹出菜单的多层顶级菜单

     LoadMenu函数

     SetMenu函数

     DestroyMenu函数    

 (c) www.bcdaren.com 编程达人

-----------------------------------------------------------------------*/

#include <windows.h>

#include "resource.h"

LRESULT CALLBACK Wndproc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )

{

     HWND hwnd;

     static TCHAR szAppName[] = TEXT("NoPopUps");

    (略)

     return msg.wParam;

}

LRESULT CALLBACK Wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)

{

     static HMENU hMenuMain,hMenuEdit,hMenuFile;//三个顶级菜单

     HINSTANCE hInstance;

     switch (message)

     {

     case WM_CREATE:

          hInstance = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);

          //加载三个独立的顶级菜单

          hMenuMain = LoadMenu(hInstance,TEXT("MenuMain"));

          hMenuEdit = LoadMenu(hInstance,TEXT("MenuEdit"));

          hMenuFile = LoadMenu(hInstance,TEXT("MenuFile"));

          //将hMenuMain设置为窗口顶级菜单

          SetMenu(hwnd,hMenuMain);

          return 0;

     case WM_COMMAND:

          switch(LOWORD(wparam))

          {

          case ID_MAIN:

               SetMenu (hwnd,hMenuMain);//将新菜单分配给指定的窗口

               return 0;

          case ID_EDIT:

               SetMenu(hwnd,hMenuEdit);

               return 0;

          case ID_FILE:

               SetMenu(hwnd,hMenuFile);

               return 0;

          case ID_FILE_NEW:

          case ID_FILE_OPEN:

          case ID_FILE_SAVE:

          case ID_FILE_SAVE_AS:    

          case ID_EDIT_UNDO:    

          case ID_EDIT_CUT:

          case ID_EDIT_COPY:

          case ID_EDIT_PASTE:

          case ID_EDIT_CLEAR:

               MessageBeep(0);

               return 0;

          }

          break;

     case WM_DESTROY:

          SetMenu(hwnd,hMenuMain);//将新菜单分配给指定的窗口

          DestroyMenu(hMenuFile);//销毁指定的菜单并释放该菜单占用的所有内存

          DestroyMenu(hMenuEdit);

          PostQuitMessage(0);

          return 0;

     }

     return DefWindowProc(hwnd,message,wparam,lparam);

}

/********************************************************************

LoadMenu函数:加载指定的菜单资源

HMENU LoadMenuA(

  HINSTANCE hInstance,//包含要加载的菜单资源的模块的句柄

  LPCSTR    lpMenuName//菜单资源名称

);

********************************************************************

SetMenu函数:将新菜单分配给指定的窗口

BOOL SetMenu(

  HWND  hWnd,//窗口句柄

  HMENU hMenu//新的菜单句柄

);

********************************************************************

DestroyMenu函数:销毁指定的菜单并释放该菜单占用的所有内存

BOOL DestroyMenu(

  HMENU hMenu//要销毁的菜单句柄

);

*/

    061_NOPOPUPS.C.rc资源脚本文件中包含3个菜单资源:

/

//

// Menu

//

MENUMAIN MENU

BEGIN

    POPUP "MAIN"

    BEGIN

        MENUITEM "FILE",                        ID_FILE

        MENUITEM "EDIT",                        ID_EDIT

    END

END

MENUFILE MENU

BEGIN

    POPUP "FILE"

    BEGIN

        MENUITEM "NEW",                         ID_FILE_NEW

        MENUITEM "OPEN",                        ID_FILE_OPEN

        MENUITEM "SAVE",                        ID_FILE_SAVE

        MENUITEM "SAVE_AS",                     ID_FILE_SAVE

        MENUITEM "MAIN",                        ID_MAIN

    END

END

MENUEDIT MENU

BEGIN

    POPUP "EDIT"

    BEGIN

        MENUITEM "UNDO",                        ID_EDIT_UNDO

        MENUITEM "CUT",                         ID_EDIT_CUT

        MENUITEM "COPY",                        ID_EDIT_COPY

        MENUITEM "PASTE",                       ID_EDIT_PASTE

        MENUITEM "CLEAR",                       ID_EDIT_CLEAR

        MENUITEM "MAIN",                        ID_MAIN

    END

END

运行结果:

图9-15 没有弹出菜单的多层顶级菜单

 

总结

实例NOPOPUPS.C给出了一个没有弹出菜单的多层顶级菜单的例子。实例在窗口过程处理WM_CREATE消息时,调用LoadMenu函数,分别加载"MenuMain"、"MenuEdit"和"MenuFile"三个菜单资源,并返回三个菜单资源的句柄。

处理WM_COMMAND消息:

点击ID_MAIN菜单时,调用SetMenu函数将"MenuMain"菜单分配给窗口。

点击ID_EDIT菜单时,调用SetMenu函数将"MenuEdit"菜单分配给窗口。

点击ID_FILE菜单时,调用SetMenu函数将"MenuFile"菜单分配给窗口。

处理WM_DESTROY消息时,调用SetMenu函数将"MenuMain"菜单分配给窗口。并调用DestroyMenu函数销毁"MenuEdit"和"MenuFile"菜单资源所占有的内存。

;