二、Windows菜单—使用系统菜单
使用WS_SYSMENU样式建立的父窗口,在其标题列的左侧有一个系统菜单按钮。如果您愿意,可以修改这个菜单。在Windows程序设计的早期,程序写作者一般把「About」菜单项放入系统菜单。虽然这种方法不常见,但是修改系统菜单往往是一种在短程序中添加菜单的快速偷懒方法。这里唯一的限制是:在系统菜单中增加的命令其ID值必须小于0xF000;否则它们将会与Windows系统菜单命令所使用的ID值相冲突。还要记住,当您为这些新菜单项在窗口消息处理程序中处理WM_SYSCOMMAND消息时,您必须把其它的WM_SYSCOMMAND消息发送给DefWindowProc。如果您不这样做,那么实际上是禁用了系统菜单上的所有正常选项。
程序10-7中所示的POORMENU(「设计不当的个人菜单」)在系统菜单中加入了一个分隔条和三个命令,最后一个命令将删除这些附加的菜单项。
程序10-7 POORMENU POORMENU.C /*------------------------------------------------------------------------- POORMENU.C -- The Poor Person's Menu (c) Charles Petzold, 1998 --------------------------------------------------------------------------*/ #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 (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { 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.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires 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) ; 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 Additions")) ; ShowWindow (hwnd, iCmdShow) ; 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) Charles Petzold, 1998"), szAppName, MB_OK | MB_ICONINFORMATION) ; return 0 ; case IDM_SYS_HELP: MessageBox ( hwnd, TEXT ("Help not yet implemented!"), szAppName, MB_OK | 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) ; }
三个菜单ID在POORMENU.C的开始部分定义:
#define IDM_ABOUT 1 #define IDM_HELP 2 #define IDM_REMOVE 3
在程序窗口建立之后,POORMENU得到一个系统菜单的句柄:
hMenu = GetSystemMenu (hwnd, FALSE) ;
第一次呼叫GetSystemMenu时,您应该为修改菜单作准备,将第二个参数设定为FALSE。
使用四个AppendMenu呼叫来实作对菜单的修改:
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 Additions"));
第一个AppendMenu呼叫是添加分隔条。选择「Remove Additions」菜单项将使POORMENU删除这些附加的菜单项,这只要把第二个参数设定为TRUE,再次呼叫GetSystemMenu即可:
GetSystemMenu (hwnd, TRUE) ;
标准系统菜单有下列选项:Restore、Move、Size、Minimize、Maximize和Close。它们产生wParam分别等于SC_RESTORE、SC_MOVE、SC_SIZE、SC_MINIMUM、SC_MAXIMUM和SC_CLOSE的WM_SYSCOMMAND消息。尽管Windows程序一般不这样做,但是您可以自己处理这些消息,而不把它们留给DefWindowProc。您也可以使用下面所述的方法来禁止或者除掉系统菜单的标准选项。Windows文件中还介绍了一些系统菜单的标准附加项目,这些附加项目使用标识符SC_NEXTWINDOW、SC_PREVWINDOW、SC_VSCROLL、SC_HSCROLL和SC_ARRANGE。您也许会发现,在一些应用程序中将这些命令加入系统菜单是合适的。