zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++windows内核编程笔记day06 代码创建菜单

2023-09-27 14:29:33 时间
BOOL AppendMenu(  HMENU hMenu,         // handle to menu
  UINT uFlags,         // menu-item options
  UINT_PTR uIDNewItem, // identifier, menu, or submenu
  LPCTSTR lpNewItem    // menu-item content
  );
 uFlags:
    MF_POPUP  -有子菜单的菜单项目,uIDNewItem要设置为子菜单的句柄(转换为uint)
    MF_SEPARATOR -分隔线
    MF_STRING    -一般菜单项,被点击后会发送消息 WM_COMMAND
    MF_MENUBREAK -换一列

把菜单加到窗口:
BOOL SetMenu(  HWND hWnd,  // handle to window  HMENU hMenu // handle to menu
);
//修改菜单的勾选状态
DWORD CheckMenuItem(  HMENU hmenu,        // handle to menu
  UINT uIDCheckItem,  // menu item to check or uncheck
  UINT uCheck         // menu item options
  );
uCheck:
    MF_BYCOMMAND  -填写菜单id
    MF_BYPOSITION -填写菜单索引
    MF_CHECKED/MF_UNCHECKED //1/0 --是否选中

//触发菜单点击事件
case WM_COMMAND:
    On_Command(hwnd,wparam);
    break;
//点击事件处理
void On_Command(HWND hwnd,WPARAM wparam)
{
    bool IsFromMenu=(HIWORD(wparam)==0?true:false);//点击菜单:0,加速键:1
    unsigned int id=LOWORD(wparam);//被点的控件id
    switch(id)
    {
    case 10011:
        //MessageBox(NULL,"打开","info",MB_OK);
        if(isChecked)
        {
            CheckMenuItem(menu1,id,MF_BYCOMMAND|MF_UNCHECKED);isChecked=false;
        }
        else{  CheckMenuItem(menu1,id,MF_BYCOMMAND|MF_CHECKED);isChecked=true;
        //MessageBox(NULL,"1","info",MB_OK);
        }
        break;
    }
}
//设置可用或不可用,与CheckMenuItem用法一样
BOOL EnableMenuItem(HMENU hMenu,// handle to menu
  UINT uIDEnableItem,  // menu item to update
  UINT uEnable         // options
  );
WM_INITMENUPOPUP  //弹出菜单在被点击还未弹出来之前触发的消息
LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_INITMENUPOPUP
  WPARAM wParam,   // handle to menu (HMENU)
  LPARAM lParam    // item position and indicator
);
lParam:
    LOWORD  被点击菜单的索引
    HIWORD  将要显示的菜单是否为窗口菜单(弹出式菜单不属于窗口菜单)

系统菜单的操作,消息:WM_SYSCOMMAND,不太重要,一般不用。
HMENU GetSystemMenu(  HWND hWnd,    // handle to window
  BOOL bRevert  // 是否返回默认菜单
  );
  AppendMenu //前面用过
 //删除菜单,根据位置删除时,删除前一个,后面一个会改变位置。
 BOOL DeleteMenu(  HMENU hMenu,     // handle to menu
  UINT uPosition,  // menu item identifier or position
  UINT uFlags      // option(MF_BYPOSITION/MF_BYCOMMAND)
  );

右键菜单:弹出式菜单,前面用过,这里主要在右键时显示菜单。
BOOL TrackPopupMenu(
  HMENU hMenu,         // handle to shortcut menu
  UINT uFlags,         // options
  int x,               // horizontal position
  int y,               // vertical position
  int nReserved,       // reserved, must be zero
  HWND hWnd,           // handle to owner window
  CONST RECT *prcRect  // ignored
);
uFlags:
    TPM_RETURNCMD  -点击菜单项,不发出WM_COMMAND消息,但有返回值(被点击菜单的ID)

//右键消息处理函数,也可以在WM_CONTEXTMENU消息中处理(专门处理)
//WM_CONTEXTMENU 在 WM_RBUTTONUP之后触发的
//WM_CONTEXTMENU 中的坐标不需要转换
void OnRButtonUp(HWND hwnd,LPARAM lparam)
{
    HMENU menucontext=CreatePopupMenu();
    AppendMenu(menucontext,MF_STRING,103,"查看");
    AppendMenu(menucontext,MF_STRING,104,"放大");
    AppendMenu(menucontext,MF_STRING,105,"缩小");
    POINT pt={0};
    pt.y=HIWORD(lparam);
    pt.x=LOWORD(lparam);
    ClientToScreen(hwnd, pt);//将客户区坐标转换为相对于屏幕的坐标
    int cmdid= TrackPopupMenu(menucontext,TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RETURNCMD,pt.x,pt.y,0,
        hwnd,NULL);//在鼠标位置显示菜单
    char txt[30]={0};
    sprintf(txt,"被点的菜单ID:%d\n",cmdid);
    MessageBox(hwnd,txt,"info",MB_OK);
}

ScreenToClient();//坐标转换函数


代码示例:

同样创建win32 application

主要cpp代码修改为:

// win32app.cpp : Defines the entry point for the application.

#include "stdafx.h"

#include stdio.h 

HINSTANCE g_hinstance=0;//全局句柄

HMENU menu1=0,menu2=0;

HANDLE g_houtput=0;

void OnCreate(HWND hwnd,LPARAM lparam)

 HMENU menu=CreateMenu();

 menu1=CreatePopupMenu();

 AppendMenu(menu1,MF_STRING|MF_CHECKED,10011,"打开");

 AppendMenu(menu1,MF_STRING,10012,"保存");

 AppendMenu(menu1,MF_SEPARATOR,0,NULL);

 AppendMenu(menu1,MF_STRING|MF_MENUBREAK,10013,"退出");

 menu2=CreatePopupMenu();

 AppendMenu(menu2,MF_STRING,10021,"复制");

 AppendMenu(menu2,MF_STRING|MF_GRAYED,10022,"粘贴");

 AppendMenu(menu,MF_POPUP,(UINT)menu1,"文件");

 AppendMenu(menu,MF_SEPARATOR,0,NULL);

 AppendMenu(menu,MF_POPUP,(UINT)menu2,"编辑");

 SetMenu(hwnd,menu);


char txt[200]={0}; sprintf(txt,"OnInitMenuPopUp:menu:%d,Index:%d,IsWindow:%d\n",wParam,index,IsWindowMenu); WriteConsole(g_houtput,txt,strlen(txt),NULL,NULL); return 0; bool isChecked=true; void On_Command(HWND hwnd,WPARAM wparam) bool IsFromMenu=(HIWORD(wparam)==0?true:false); unsigned int id=LOWORD(wparam); switch(id) case 10011: //MessageBox(NULL,"打开","info",MB_OK); if(isChecked) CheckMenuItem(menu1,id,MF_BYCOMMAND|MF_UNCHECKED);isChecked=false; else{ CheckMenuItem(menu1,id,MF_BYCOMMAND|MF_CHECKED);isChecked=true; //MessageBox(NULL,"1","info",MB_OK); break; void OnSysCommand(HWND hwnd,WPARAM wparam) bool IsFromMenu=(HIWORD(wparam)==0?true:false); unsigned int id=LOWORD(wparam); switch(id) case 101: MessageBox(hwnd,"我的菜单","info",MB_OK); break; default: //MessageBox(hwnd,"我的菜单1","info",MB_OK); break; void OnRButtonUp(HWND hwnd,LPARAM lparam) // HMENU menucontext=CreatePopupMenu(); // AppendMenu(menucontext,MF_STRING,103,"查看"); // AppendMenu(menucontext,MF_STRING,104,"放大"); // AppendMenu(menucontext,MF_STRING,105,"缩小"); // POINT pt={0}; // pt.y=HIWORD(lparam); // pt.x=LOWORD(lparam); // ClientToScreen(hwnd, pt);//将客户区坐标转换为相对于屏幕的坐标 // int cmdid= TrackPopupMenu(menucontext,TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RETURNCMD,pt.x,pt.y,0, // hwnd,NULL);//在鼠标位置显示菜单 // char txt[30]={0}; // sprintf(txt,"被点的菜单ID:%d\n",cmdid); // MessageBox(hwnd,txt,"info",MB_OK); void OnContextMenu(HWND hwnd,LPARAM lparam) HMENU menucontext=CreatePopupMenu(); AppendMenu(menucontext,MF_STRING,103,"查看"); AppendMenu(menucontext,MF_STRING,104,"放大"); AppendMenu(menucontext,MF_STRING,105,"缩小"); POINT pt={0}; pt.y=HIWORD(lparam); pt.x=LOWORD(lparam); //ClientToScreen(hwnd, pt);//将客户区坐标转换为相对于屏幕的坐标 int cmdid= TrackPopupMenu(menucontext,TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RETURNCMD,pt.x,pt.y,0, hwnd,NULL);//在鼠标位置显示菜单 if(cmdid!=0){ char txt[30]={0}; sprintf(txt,"被点的菜单ID:%d\n",cmdid); MessageBox(hwnd,txt,"info",MB_OK); //回调函数 LRESULT CALLBACK WinProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam) switch(msg) case WM_SYSCOMMAND: if(wparam==SC_CLOSE){ int ret=MessageBox(NULL,"是否退出","info",MB_YESNO); if(ret==IDYES){ //下面代码会自动关闭和销毁 //PostQuitMessage(0); else return 0;//不执行下面代码 OnSysCommand(hwnd,wparam); break; //在创建窗口之后还未显示的时候 case WM_CREATE: OnCreate(hwnd,lparam); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_COMMAND: On_Command(hwnd,wparam); break; case WM_INITMENUPOPUP: OnInitMunuPopUp(hwnd,msg,wparam,lparam); break; case WM_RBUTTONUP: OnRButtonUp(hwnd,lparam); break; case WM_CONTEXTMENU: OnContextMenu(hwnd,lparam); break; return DefWindowProc(hwnd,msg,wparam,lparam); //注册窗口类 BOOL Register(LPSTR lpClassName,WNDPROC wndproc) WNDCLASSEX wce={0}; wce.cbSize=sizeof(wce); wce.cbClsExtra=200; wce.cbWndExtra=200; wce.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); wce.hCursor=NULL; wce.hIcon=NULL; wce.hIconSm=NULL; wce.hInstance=g_hinstance; wce.lpfnWndProc=wndproc; wce.lpszClassName=lpClassName; wce.lpszMenuName=NULL; wce. "注册失败","info",MB_OK); return FALSE; return TRUE; //创建窗口 HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName) HWND hwnd=CreateWindowEx(0,lpClassName,lpWndName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,g_hinstance,"hello create"); return hwnd; //创建子窗口 HWND CreateChild(HWND phwnd,LPSTR lpClassName,LPSTR lpWndName) if(Register(lpClassName,DefWindowProc)==0) MessageBox(phwnd,"创建子窗口失败","info",MB_OK); return NULL; //子窗口风格,都要 WS_CHILD|WS_VISIBLE HWND hwnd=CreateWindowEx(0,lpClassName,lpWndName,WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT, 200,200,phwnd,NULL,g_hinstance,NULL); return hwnd; //显示窗口 void Display(HWND hwnd) ShowWindow(hwnd,SW_SHOW); UpdateWindow(hwnd); //处理消息 void MSGdeal() MSG msg={0}; while(GetMessage( msg,NULL,0,0)){ TranslateMessage( msg);//翻译消息 DispatchMessage( msg);//派发给 WinProc 处理消息
进程是一个容器,包含程序执行需要的代码、数据、资源等信息, windows进程的特点:每个进程都有自己的ID号每个进程都有自己的地址空间,进程之间无法访问对方的地址空间。
windows库程序:静态库: 源代码被链接到调用的程序或动态库,被调用时,代码最少有1份,文件后缀.LIB 动态库: 函数被程序或其他动态库调用,被调用时,代码只有1份,文件后缀.