目录
在case里面定义了变量一定要加大括号!
一、菜单分类:
- 系统菜单:点击窗口图标出来的菜单
- 右键菜单(弹出式菜单):在应用程序的客户区,单击鼠标右键弹出的菜单
- 顶层菜单(菜单栏菜单)
菜单和菜单项的区别:
- 菜单:整个
- 菜单项:菜单中的一项
二、系统菜单
创建系统菜单:
- 获取菜单句柄:GetSystemMenu
HMENU hSystemMenu = GetSystemMenu(hwnd,false);
- 添加菜单项:AppendMenu
BOOL AppendMenu( HMENU hMenu,//菜单句柄(添加到那个菜单下) UINT uFlags,//设置方式 UINT_PTR uIDNewItem,//设置该菜单项id LPCSTR lpNewItem//新菜单项指针 ); //方式有两种: /* MF_SEPARATOR分隔符(对应的第四个菜单项为NULL) MF_STRING字符串(对应的第四个参数为字符串的内容) */
void OnCreate(HWND hwnd){ HMENU hSystemMenu = GetSystemMenu(hwnd,false); AppendMenu(hSystemMenu,MF_STRING,1,"菜单项1"); AppendMenu(hSystemMenu,MF_STRING,2,"菜单项2"); AppendMenu(hSystemMenu,MF_STRING,3,"菜单项3"); }
#include <windows.h> HMENU g_hPopupMenu; void OnCreate(HWND hwnd){ g_hPopupMenu = CreatePopupMenu(); AppendMenu(g_hPopupMenu,MF_STRING,1,"功能1"); AppendMenu(g_hPopupMenu,MF_STRING,2,"功能2"); AppendMenu(g_hPopupMenu,MF_STRING,3,"功能3"); AppendMenu(g_hPopupMenu,MF_STRING,4,"功能4"); } POINT getPos(LPARAM lParam){ POINT pos; pos.x = LOWORD(lParam); pos.y = HIWORD(lParam); return pos; } void displayMenu(HWND hwnd,int x,int y){ RECT rect = {0}; TrackPopupMenu(g_hPopupMenu,TPM_CENTERALIGN,x,y,0,hwnd,&rect); } /* This is where all the input to the window goes to */ LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_CREATE: OnCreate(hwnd); break; case WM_RBUTTONUP:{ POINT pos = getPos(lParam); displayMenu(hwnd,pos.x,pos.y); break; } /* trap the WM_CLOSE (clicking X) message, and actually tell the window to close */ case WM_CLOSE: { DestroyWindow(hwnd); break; } /* Upon destruction, tell the main thread to stop */ case WM_DESTROY: { PostQuitMessage(0); break; } /* All other messages (a lot of them) are processed using default procedures */ default: return DefWindowProc(hwnd, Message, wParam, lParam); } return 0; }
- 删除菜单项:DeleteMenu
- 菜单项对应的消息处理
- 虽然是鼠标点击动作,但是所有的点击菜单项的动作,触发的都是WM_COMMAND消息!特别注意系统菜单触发的是WM_SYSCOMMAND;我们的消息处理函数的思路就是通过ID来辨别用户点击了那个菜单项
- WM_COMMAND(WM_SYSCOMMAND)的附加消息
- id = LOWORD(wParam)
- event = HIWORD(wParam)
-
case WM_SYSCOMMAND: Id = LOWORD(wParam); switch(Id){ case 1: MessageBox(hwnd,"点击了菜单项1","系统菜单项",MB_OK); break; case 2: MessageBox(hwnd,"点击了菜单项2","系统菜单项",MB_OK); break; case 3: MessageBox(hwnd,"点击了菜单项3","系统菜单项",MB_OK); break; default: return DefWindowProc(hwnd,Message,wParam,lParam); } break;
注意:一定要在default中设置其他情况调用默认的消息处理函数,否则,系统菜单的其他功能将无法使用,比如说从系统菜单关闭窗口应用程序。
使用系统菜单
- 设置菜单项的处理函数:做对应消息处理
- 追加菜单项 AppendMenu
- 删除菜单项 DeleteMenu
-
DeleteMenu(
HMENU hMenu,菜单句柄
UINT uPosition,位置
UINT uFlags); 方式-
方式有两种:索引(MF_BYPOSITION):第几个 从0开始 下标(MY_BYCOMMAND):
-
WM_COMMAND消息:wParam保存菜单项id
-
WM_SYSCOMMAND消息:点击系统菜单项就会产生WM_SYSCOMMAND消息,不同的系统菜单项会产生不同的WM_SYSCOMMAND消息,这些消息的wParam中保存的菜单项id号不同
-
-
三、顶层菜单(菜单栏菜单)
- 创建顶层菜单 HMENU hTopMenu = CreateMenu();
- 创建顶层菜单的子菜单(弹出式菜单)HMENU hPopMenu = CreatePopupMenu();
- 把弹出式菜单添加到顶层菜单的子菜单中 AppendMenu(hTopMenu,MF_POPUP,(UINT_PTR)hPopMenu,"pop1");弹出式菜单并不需要设置消息处理函数,因为只要风格设置MF_POPUP,那么当我们点击这个弹出菜单时,默认的响应动作就是弹出子菜单!
- 添加弹出式菜单的菜单项 AppendMenu(hPopMenu,MF_STRING,设置其ID号,设置其名字);只有风格为MF_STRING类型的菜单项才需要设置ID号,并且设置ID号对应的消息处理函数(WM_COMMAND)。
- 显示 设置 SetMenu(hwnd,hTopMenu);
- 获取弹出式菜单的子菜单句柄
- HMENU hTop = GetMenu(hwnd) ;用来获取顶层菜单的句柄,有人要奇怪,我们在创建顶层菜单时不是已经得到了顶层菜单的句柄了吗?其实这个函数是用来在消息处理函数中使用的。当用户执行了某些操作后,我们需要对顶层菜单进行操作,就需要得到顶层菜单的句柄,只有在得到顶层菜单的句柄后,才能进一步得到其子菜单的句柄。
- HMENU hChild = GetSubMenu(hTop,第几个子菜单)获取顶层菜单的第x个子菜单的句柄。
- GetSubMenu(hChild,xxx)获取子菜单的第几个子子菜单的句柄。
-
case WM_COMMAND:{ int id = LOWORD(wParam); switch(id){ case 7:{ MyPrintf("%s","菜单项1"); HMENU hTop = GetMenu(hwnd);//获取顶层菜单的句柄 HMENU hChild1 = GetSubMenu(hTop,0); CheckMenuItem(hChild1,0,MF_CHECKED|MF_BYPOSITION); break; } case 8: MyPrintf("%s","菜单项2"); break; } break; }
-
- 设置弹出式菜单的子菜单
- CheckMenuItem(句柄,位置,风格)设置句柄(应该是要选中的菜单项的上一级菜单)的第位置个子菜单被选中
- MF_CHECKED 设置被选中
- MF_UNCHECKED 取消被选中
- 注意位置下标是从0 开始的。
- EnabelMenuItem(上层菜单句柄,菜单项ID,MF_GRAYD)非使能菜单项(灰色,不能选中,设置是否可选中)
- CheckMenuItem(句柄,位置,风格)设置句柄(应该是要选中的菜单项的上一级菜单)的第位置个子菜单被选中
-
void OnCreate(HWND hwnd){ HMENU hTopMenu = CreateMenu(); HMENU hChild = CreatePopupMenu(); AppendMenu(hTopMenu,MF_POPUP,(UINT_PTR)hChild,“子菜单1”); AppendMenu(hChild,MF_STRING,007,“孙子菜单”); SetMenu(hwnd,hTopMenu); }
方法二:在添加资源时,添加菜单,然后设置菜单ID,在注册窗口类时,设置显示。具体操作方法见,《重要消息》第二部分10分。实际开发中,方法二应用的更多,因为更加方便。
四、右键菜单
- 在WM_CREATE的时候创建弹出式菜单
- CreatePopupMenu
-
HMENU hPopupMenu = CreatePopupMenu();
- 在WM_CREATE的时候添加菜单项
- AppendMenu
- DeleteMenu
- 右键单击的时候显示菜单
- TrackPopupMenu
-
BOOL TrackPopupMenu( HMENU hMenu, //菜单句柄 UINT uFlags,//方式 int x, int y,//坐标 int nReserved, //保留的,为了以后给函数加参数方便 HWND hWnd, //窗口句柄 LPCRECT prcRect //矩形 );
- 消息处理
- WM_CONTEXTMENU触发:当你单击右键并弹起的时候,两种消息都会发送。但是右键消息中附加消息lParam记录的是当前光标右键弹起处的屏幕坐标(低位x,高位y),WM_CONTEXTMENU中附加消息lParam记录的是右键弹起时的光标的窗口客户区坐标。
-
#include <windows.h> #include "stdafx.h" #include "Resource.h" #include <stdio.h> #include <cstdio> #include <string.h> #include <cstring> HINSTANCE g_hInstance; HCURSOR g_hCursor1, g_hCursor2;//光标句柄 MSG msg;//声明一个MSG类型的消息结构体 HANDLE g_hConsole;//定义一个HANDLE类型的全局变量,之后要将命令行窗口句柄赋值给它,命名时养成习惯:如果是全局变量以g_开头命名它。 HMENU hRight; int flag = 0; //写一个windows窗口 //5定义消息处理函数 void OnCreate(HWND hWnd,WPARAM wParam,LPARAM lParam) { #if 0 //一 系统菜单 HMENU hSystemMenu=GetSystemMenu(hWnd, 0);//获取系统菜单句柄 //删除系统菜单项:系统菜单有七项,其中分隔符也算菜单项 for (int i = 0; i < 6; i++) { DeleteMenu(hSystemMenu, 0, MF_BYPOSITION);//按照索引的方式删除,0表示当前状况的第一个,是变化的 //DeleteMenu(hSystemMenu, 0, MF_BYCOMMAND);//按照下标的方式删除,0表示初期情况下菜单栏的第一个(即分隔符),是固定的。 } //追加系统菜单项:追加就一定在最后追加 AppendMenu(hSystemMenu, MF_SEPARATOR, 1111, NULL);//第二个参数决定菜单项的样式:分隔符(MF_SEPARATOR)还是字符串,如果第二个参数选分隔符,那么第三个参数就是分隔符的id AppendMenu(hSystemMenu, MFT_STRING, 1112, L"(ง •_•)ง(M)");//第二个参数如果是字符串,则最后一个参数为字符串的内容。 //这里只能决定菜单的样子,而真正地处理才是关键。 /*真正的处理在消息处理函数中,系统菜单的消息由WM_COMANND消息管理*/ #endif //二、顶层菜单 HMENU hTopMenu = CreateMenu();//创建顶层菜单,返回顶层菜单的句柄 //创建弹出式菜单 HMENU hChinese = CreatePopupMenu(); HMENU hJapan = CreatePopupMenu(); HMENU hAmerican = CreatePopupMenu(); HMENU hSearch = CreatePopupMenu(); //将弹出式菜单添加到顶层菜单中 AppendMenu(hTopMenu,MF_POPUP,(UINT)hChinese,L"国产");//第三个参数需要弹出式菜单的id,我们将句柄强制转化成id类型 AppendMenu(hTopMenu, MF_POPUP, (UINT)hJapan,L"日本"); AppendMenu(hTopMenu, MF_POPUP, (UINT)hAmerican,L"欧美"); AppendMenu(hJapan, MF_POPUP, (UINT)hSearch,L"搜索"); //添加菜单项到弹出式菜单中 //添加到国产中 AppendMenu(hChinese, MF_STRING,2511, L"土肥圆矮穷挫");//第三个参数为你设置的这个菜单项的id AppendMenu(hChinese, MF_STRING, 2512, L"艾栗栗"); AppendMenu(hChinese, MF_STRING, 2513, L"萌琪琪"); AppendMenu(hChinese, MF_STRING, 2514, L"张柏芝艳照门"); //添加到日本中 AppendMenu(hJapan, MF_STRING, 2521, L"波多野结衣");//第三个参数为你设置的这个菜单项的id AppendMenu(hJapan, MF_STRING, 2522, L"泷泽萝拉"); AppendMenu(hJapan, MF_STRING, 2523, L"桃谷绘里香"); AppendMenu(hJapan, MF_STRING, 2524, L"桃乃木香奈"); AppendMenu(hJapan, MF_STRING, 2524, L"其他"); AppendMenu(hJapan, MF_STRING, 2525, L"选中泷泽萝拉"); //添加到欧美中 AppendMenu(hAmerican, MF_STRING, 2531, L"安洁莉卡"); //添加菜单项到搜索中 AppendMenu(hSearch, MF_STRING, 2541, L"搜索番号"); AppendMenu(hSearch, MF_STRING, 2541, L"搜索女优"); AppendMenu(hSearch, MF_STRING, 2541, L"搜索男优"); //显示顶层菜单 SetMenu(hWnd, hTopMenu); //获取菜单项句柄,现在只有我自己设置的菜单项的id HMENU hTemp = GetSubMenu(hJapan, 0);//得到波多野结衣菜单项的句柄 //设置菜单项 EnableMenuItem(hJapan, 2521,MF_GRAYED);//第一个参数为菜单项所在弹出式菜单的句柄,第二参数该菜单项的id,设置菜单项“波多野结衣”为灰色 //三、创建右键菜单 hRight = CreatePopupMenu(); AppendMenu(hRight, MF_STRING, 3001, L"打开男人团"); AppendMenu(hRight, MF_STRING, 3002, L"打开福利档"); AppendMenu(hRight, MF_STRING, 3003, L"打开torrentkitty"); } LRESULT CALLBACK WndProc(HWND hWnd,//窗口句柄 //CALLBACK表示是一个回调函数,LRESULT是函数返回值的类型,可以通过查看wc.lpfnWndProc的定义查看 UINT code,//消息 msg.message WPARAM wParam,//消息附加信息 LPARAM lParam//消息附加信息 ) { HMENU hGet; RECT rect; //用switch case 来判断是什么消息 switch (code) { case WM_CONTEXTMENU: GetWindowRect(hWnd, &rect);//获取当前窗口客户区的矩形,传参给rect TrackPopupMenu(hRight, TPM_RIGHTBUTTON, LOWORD(lParam), HIWORD(lParam), 0, hWnd, &rect);//右键点击时显示菜单 break; #if 0 case WM_RBUTTONUP://当单击右键并弹起时,会收到此消息 //TrackPopupMenu() GetWindowRect(hWnd, &rect);//获取当前窗口客户区的矩形,传参给rect TrackPopupMenu(hRight, TPM_CENTERALIGN, rect.left+LOWORD(lParam),rect.top+HIWORD(lParam), 0, hWnd, &rect);//右键点击时显示菜单 break;//用这种方式右键菜单弹出的位置有点问题,因为WM_RBUTTONUP的lParam中存储的是相对于桌面的xy坐标,需要用当前窗口即rect.left+LOWOR(lParam)转化成相对于窗口的。 #endif break; case WM_SYSCOMMAND://点击系统菜单项就会产生WM_SYSCOMMAND消息 switch (wParam) {//不同的系统菜单项会产生不同的WM_SYSCOMMAND消息,这些消息的wParam中保存的菜单项id号不同 case 1112://之前我们自己追加的菜单项id号为1112 MessageBox(hWnd, L"(ง •_•)ง", L"系统菜单项", NULL); break; default: break; } break; case WM_KEYDOWN: break; case WM_COMMAND://当点击菜单项时会发送WM_COMMAND消息,由于不同的菜单项我们设置了不同的id,所以可以根据菜单项的id来区分 switch (wParam) {// 点击不同的菜单项,WM_COMMAND的附加消息wParam中存储的id号不同 case 2522: MessageBox(hWnd, L"泷泽萝拉的作品目前还没有", L"抱歉", MB_OK); break; //点击 桃乃木香奈 2524 菜单项 设置 波多野结衣菜单项 2521 可选中(由灰色变成黑色) //点击 波多野结衣 2521 菜单项 设置 桃谷绘里香 2523 菜单项选中 case 2524: hGet =GetSubMenu(GetMenu(hWnd),1);//GetMenu拿到的是窗口句柄为hWnd的窗口的顶层菜单的菜单句柄;以之作为参数去拿顶层菜单的弹出式菜单 EnableMenuItem(hGet, 2521, MF_ENABLED);//设置波多野结衣菜单项为黑色 break; case 2521: hGet = GetSubMenu(GetMenu(hWnd), 1); //通过id号来选中桃谷绘里香菜单项 //CheckMenuItem(hGet, 2523, MF_CHECKED);//设置桃谷绘里香被选中 //通过相对位置来选中桃谷绘里香 菜单项 CheckMenuItem(hGet, 3, MF_CHECKED | MF_BYPOSITION); break; case 2525: hGet = GetSubMenu(GetMenu(hWnd), 1); switch (flag) { case 0: CheckMenuItem(hGet, 2522, MF_CHECKED); flag = 1; break; case 1: CheckMenuItem(hGet, 2522, MF_UNCHECKED); flag = 0; break; } break; } break; case WM_MOUSEMOVE: break; case WM_CREATE://代表窗口创建消息 OnCreate(hWnd, wParam, lParam); break; case WM_PAINT://绘图消息 break; case WM_DESTROY: PostQuitMessage(0);//PostQuitMessage函数发送一个WM_QUIT消息到线程消息队列并且立即返回 break; default: return DefWindowProc(hWnd, code, wParam, lParam);//意味着开始下一次消息循环 } return DefWindowProc(hWnd, code, wParam, lParam);//意味着开始下一次消息循环 } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hParentInstance, LPSTR lpCmd, int len) { g_hInstance = hInstance; //1.写主函数 //2.在主函数中注册窗口类 WNDCLASS WNDCLASSEX(64位扩展的) WNDCLASSEX wc;//wc是一个窗口类 类型的 结构体,它里面有很多成员变量,一个一个给它们初始化就可以了 wc.cbSize = sizeof(WNDCLASSEX);//窗口类大小 wc.cbClsExtra = NULL;//窗口类附加信息 即 对窗口类的说明 等于NULL表示没有附加信息 wc.cbWndExtra = NULL;//窗口附加信息 即对窗口的说明 wc.lpszClassName = L"番号搜索大法";//窗口类名,主要是为了标志版权 用spy++工具可以查看类名 //wc.hbrBackground=NULL;//背景 设置背景颜色 wc.hbrBackground = (HBRUSH)GetStockObject(3);//百度查,记不住 wc.hCursor = NULL; //wc.hIcon = NULL;//窗口的图标(任务栏) 用loadicon函数来加载图标:加载一个图标资源,并且返回这个图标资源的句柄。 wc.hIcon = NULL; //两种方式loadIcon和(HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_ICON2),IMAGE_ICON,32,32,LR_LOADTANSPARENT); //加载方式:LR_LOADTANSPARENT资源方式加载,文件方式加载LOADFROMFILE wc.hIconSm = NULL;//小图标 wc.hInstance = hInstance;//当前应用程序的实例句柄 wc.lpfnWndProc = WndProc; //消息处理函数=你自己定义的消息处理函数的名字 wc.lpszMenuName = NULL; //菜单 wc.style = CS_HREDRAW | CS_VREDRAW;//窗口风格=水平/垂直滚动条 RegisterClassEx(&wc); //正式注册窗口类,只要把结构体wc的地址传入即可。 //3.创建窗口 CreateWindow //HWND 窗口句柄类型 Handle Window HWND hWnd = CreateWindowEx( //因为创建窗口函数会返回创建的窗口的句柄,所以首先定义好窗口句柄类型的变量。 NULL,//窗口的附加风格 wc.lpszClassName, //窗口类名 L"番号搜索大法",//窗口名 WS_OVERLAPPEDWINDOW,//窗口的风格 1000, 100,//窗口出现的位置 (x,y) 600, 600,//窗口的宽高 NULL,//父窗口实例句柄 NULL,//窗口的菜单的句柄 hInstance,//窗口的实例句柄(当前应用程序实例句柄 NULL);//附加信息 消息是个结构体,消息有两个附加信息:lParam wParam /*如果创建窗口失败,则CreateWindow的返回值为NULL即0; *如果创建窗口成功,则CreateWindow的返回值为所创建窗口的句柄 */ /* if(NULL==hWnd){ MessageBox(NULL,"创建窗口失败","警告",MB_OK); return -1; } else{ MessageBox(NULL,"创建窗口成功","恭喜",MB_OK); } */ //4.显示刷新窗口 ShowWindow updateWindow ShowWindow(hWnd, 5);//传入窗口的句柄即可。 UpdateWindow(hWnd); //传入窗口的句柄即可。 AllocConsole();//得到命令行窗口使用权限 g_hConsole = GetStdHandle(STD_OUTPUT_HANDLE);//用函数得到命令行窗口句柄,赋值给全局变量g_hConsole //5.定义窗口的消息处理函数 //消息循环是一个死循环,永远不会结束,除非。。。你写一个语句break while (1) { //获取消息 //GetMessage(&msg, NULL, NULL, NULL);//GetMessage函数是一个阻塞函数,如果接收一个消息所用的时间过长,在此期间内,如果有另一个消息被发送,就会接受不到这个消息 if (PeekMessage(&msg, NULL, NULL, NULL, NULL))//最后一个参数表示是否删除消息 /*PeekMessage的工作原理:非阻塞方式接受消息,主要查看是否有消息,不会将消息存入MSG结构体中,GetMessage函数负责将消息存入MSG结构体中。 Peekmessage会检查消息队列,如果消息队列中有消息,函数就会查看最后一个参数, 如果最后一个参数为false或者NULL,直接返回1 如果最后一个参数为true,从消息队列中删除消息,然后返回1 如果消息队列中没有消息,直接返回0 */ { if (0 == GetMessage(&msg, NULL, NULL, NULL)) break; /*GetMessage工作原理: GetMessage从消息队列中获取一个消息存放到MSG结构体中。 如果消息队列中有消息,把消息存入MSG,删除当前程序消息队列中的消息,返回非0 直到遇到WM_QUIT消息才返回0.注意:关闭窗口不会发送WM_QUIT消息,只会发送WM_DESTROY消息,只有在消息处理函数中定义当收到WM_DESTROY时,向消息队列中添加WM_QUIT消息, 才能通过if(0 == GetMessage(&msg, NULL, NULL, NULL)) break;退出循环。 如果当前程序消息队列中没有消息,就去系统消息队列中看有没有消息。如果系统消息队列 里面有消息,就把系统消息队列中的消息放入当前程序消息队列。如果系统消息队列中没有消息,就 检查窗口是否需要重新绘制。如果需要重新绘制,操作系统发送WM_PAINT消息,如果不需要重新绘制 查看是否有定时器,如果有定时器,处理定时器消息,如果没有定时器,优化资源,处理内存,继续等待。 消息循环处理消息的次数可能小于消息处理函数处理消息的次数,因为其他应用程序的消息也可能发送给消息处理函数处理。 */ /* if (msg.message == WM_QUIT) { //WM_QUITE消息表示整个窗口退出 break; } */ //翻译消息 TranslateMessage(&msg);//翻译消息 /*消息的翻译主要针对键盘消息,键盘消息只有两个: WM_TDOWN WM_TUP if(msg.message==WM_KEY 按键消息){ if(是否可见字符){//可见字符即代表字符有回显,例如F1F2..PgUp等不是可见字符。 //如果是可见字符,代表应该告诉应用程序,用户按键是用来编辑,发送的是一个字符,否则,就认为用户按键是发送一个指令。 //如果用户发送的是一个字符,就需要翻译一下 if(Caps Lock是否按下){ PostMessage(大写字母消息);//发送大写字母消息 }else{ PostMessage(小写字母消息);//发送小写字母消息 } } } return; */ DispatchMessage(&msg);//派发消息,群发消息,给当前所有的应用程序都发送。而PostMessage表示只对当前应用程序的消息处理函数发送消息。 } } //6.消息循环 循环 接受消息 翻译消息 派发消息 //点击动作 操作系统产生消息 发给窗口应用程序,应用程序里面的“消息循环”接收消息,调用对应的消息处理函数,产生对应的响应动作。 return 0; }
-
WINAPI
TrackPopupMenu(
HMENU hMenu,//要显示的菜单句柄
UINT uFlags, //方式(弹出菜单位于光标的右下方,还是右上方) 只要是方式就有对应的宏,这些宏的前缀是TPM_
int x, int y, //显示的坐标
int nReserved, //保留值,必须为0
HWND hWnd,//窗口句柄
CONST RECT *prcRect);//当前窗口应用程序的矩形区域 - 右键消息WM_RBUTTONUP触发:
-
- WM_CONTEXTMENU触发:当你单击右键并弹起的时候,两种消息都会发送。但是右键消息中附加消息lParam记录的是当前光标右键弹起处的屏幕坐标(低位x,高位y),WM_CONTEXTMENU中附加消息lParam记录的是右键弹起时的光标的窗口客户区坐标。
Appendmenu的参数uflags
uFlags [in]
Type: UINT
Controls the appearance and behavior of the new menu item. This parameter can be a combination of the following values.
Value | Meaning |
---|---|
MF_BITMAP 0x00000004L | Uses a bitmap as the menu item. The lpNewItem parameter contains a handle to the bitmap. |
MF_CHECKED 0x00000008L | Places a check mark next to the menu item. If the application provides check-mark bitmaps (see SetMenuItemBitmaps, this flag displays the check-mark bitmap next to the menu item. |
MF_DISABLED 0x00000002L | Disables the menu item so that it cannot be selected, but the flag does not gray it. |
MF_ENABLED 0x00000000L | Enables the menu item so that it can be selected, and restores it from its grayed state. |
MF_GRAYED 0x00000001L | Disables the menu item and grays it so that it cannot be selected. |
MF_MENUBARBREAK 0x00000020L | Functions the same as the MF_MENUBREAK flag for a menu bar. For a drop-down menu, submenu, or shortcut menu, the new column is separated from the old column by a vertical line. |
MF_MENUBREAK 0x00000040L | Places the item on a new line (for a menu bar) or in a new column (for a drop-down menu, submenu, or shortcut menu) without separating columns. |
MF_OWNERDRAW 0x00000100L | Specifies that the item is an owner-drawn item. Before the menu is displayed for the first time, the window that owns the menu receives a WM_MEASUREITEM message to retrieve the width and height of the menu item. The WM_DRAWITEM message is then sent to the window procedure of the owner window whenever the appearance of the menu item must be updated. |
MF_POPUP 0x00000010L | Specifies that the menu item opens a drop-down menu or submenu. The uIDNewItem parameter specifies a handle to the drop-down menu or submenu. This flag is used to add a menu name to a menu bar, or a menu item that opens a submenu to a drop-down menu, submenu, or shortcut menu. |
MF_SEPARATOR 0x00000800L | Draws a horizontal dividing line. This flag is used only in a drop-down menu, submenu, or shortcut menu. The line cannot be grayed, disabled, or highlighted. The lpNewItem and uIDNewItem parameters are ignored. |
MF_STRING 0x00000000L | Specifies that the menu item is a text string; the lpNewItem parameter is a pointer to the string. |
MF_UNCHECKED 0x00000000L | Does not place a check mark next to the item (default). If the application supplies check-mark bitmaps (see SetMenuItemBitmaps), this flag displays the clear bitmap next to the menu item. |