/*------------------------------------------------------------------------
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"菜单资源所占有的内存。