首页 > 代码库 > 走进windows编程的世界-----消息处理函数(3)

走进windows编程的世界-----消息处理函数(3)

二 定时器消息

 1 定时器消息 WM_TIMER
   依照定时器设置时间段,自己主动向窗体发送一个定时器消息WM_TIMER. 优先级比較低.
   定时器精度比較低,毫秒级别.消息产生时间也精度比較低.
   
 2 消息和函数
   2.1 WM_TIMER  - 消息ID
    wParam: 定时器的ID
    lParam: 定时器的处理函数

   2.2 SetTimer  - 设置一个定时器

UINT SetTimer(
HWND hWnd, //窗体的句柄,能够为NULL
UINT nIDEvent,//定时器的ID,0为不预设ID
UINT uElapse,//定时器时间间隔,毫秒级别
TIMERPROC lpTimerFunc );//定时器的处理函数,能够为NULL

   返回一个创建好的定时器ID

  2.3 KillTimer - 结束一个定时器

BOOL KillTimer(
      HWND hWnd,//窗体句柄
      UINT uIDEvent );//定时器ID

  2.4 TimerProc - 定时器处理函数

VOID CALLBACK TimerProc(
    HWND hwnd, //窗体句柄
    UINT uMsg, //WM_TIMER消息ID
    UINT idEvent,//定时器ID
    DWORD dwTime   );//当前系统时间

  3 使用方式
    3.1 创建定时器 SetTimer
     3.1.1 指定窗体句柄HWND,那么 TIMERPROC 參数能够为空,那么WM_TIMER消息将会发送给指定窗体. 假设未指定, TIMERPROC不能空, 必须指定定时器处理程序.
     3.1.2 假设指定定时器ID,SetTimer会依照这个ID创建定时器, 假设未指定,会返回一个创建定时器ID.

nTimerID = SetTimer( NULL, 0, 7 * 1000,TimerProc1 );

    3.2 处理消息
      能够依据消息传入定时器ID号,分别处理.
    3.3 结束定时器
      在不使用时, KillTimer结束定时器

/* File : winpaint.cpp 
 * Auth : sjin 
 * Date : 20140706 
 * Mail : 413977243@qq.com 
 */  
  
#include <Windows.h>  
#include <stdio.h>

HINSTANCE g_hInst   = NULL;
HANDLE    g_hStdOut = NULL;
UINT      g_nTimerID1 = 0;


/*定时器处理函数*/
void CALLBACK TimerProc1( HWND hWnd,
                          UINT nMsg,
                          UINT idEvent,
                          DWORD dwTime )
{
    CHAR szText[] = "TimerProc1: Hello Timer\n";
    WriteConsole( g_hStdOut, szText,
        strlen(szText), NULL, NULL );
}

void OnCreate( HWND hWnd, UINT nMsg,
    WPARAM wParam, LPARAM lParam )
{
	/*
	UINT SetTimer(
		HWND hWnd, //窗体的句柄,能够为NULL
		UINT nIDEvent,//定时器的ID,0为不预设ID
		UINT uElapse,//定时器时间间隔,毫秒级别
		TIMERPROC lpTimerFunc );//定时器的处理函数,能够为NULL

		return : 创建好的定时器的ID号
	*/
    //使用窗体处理函数,创建2个定时器
    SetTimer( hWnd, 1000, 3 * 1000, NULL );    
    SetTimer( hWnd, 1001, 5 * 1000, NULL );
    //使用窗体处理函数, 未指明定时器ID
    g_nTimerID1 = SetTimer( hWnd, 0, 2* 1000, NULL );
    //使用TimerProc处理函数创建定时器
    //SetTimer( hWnd, 1002, 7 * 1000, TimerProc1 );
	SetTimer( hWnd, 1002, 7 * 1000, NULL );
}

void OnTimer( HWND hWnd, UINT nMsg,
    WPARAM wParam, LPARAM lParam )
{
    switch( wParam )
    {
    case 1000:
        {
            CHAR szText[] = "1000: Hello Timer\n";
            WriteConsole( g_hStdOut, szText,
                strlen(szText), NULL, NULL );
        }
        break;
    case 1001:
        {
            CHAR szText[] = "1001: Hello Timer\n";
            WriteConsole( g_hStdOut, szText,
                strlen(szText), NULL, NULL );
        }
        break;
    case 1002:/*1002 设置对应的处理函数,不会在这里调用*/
        {
            CHAR szText[] = "1002: Hello Timer\n";
            WriteConsole( g_hStdOut, szText,
                strlen(szText), NULL, NULL );
        }
        break;
    default:
        {
            CHAR szText[260] = {0};
            sprintf( szText, "%d: Hello Timer\n",
                g_nTimerID1 );
            WriteConsole( g_hStdOut, szText,
                strlen(szText), NULL, NULL );
        }
        break;
    }
}

LRESULT CALLBACK WndProc( HWND hWnd,
                          UINT nMsg,
                          WPARAM wParam,
                          LPARAM lParam )
{
    switch( nMsg )
    {
    case WM_CREATE:
        OnCreate( hWnd, nMsg, wParam, lParam );
        break;
    case WM_TIMER:/*处理定时器事件,没有设置定时器回调函数的*/
        OnTimer( hWnd, nMsg, wParam, lParam );
        break;
    case WM_DESTROY:
		/*销毁定时器
		BOOL KillTimer(
			HWND hWnd,//窗体句柄
			 UINT uIDEvent );//定时器ID
		*/
        KillTimer( hWnd, 1000 );
		KillTimer( hWnd, 1001 );
		KillTimer( hWnd, 1002 );
		KillTimer( hWnd, g_nTimerID1 );
        PostQuitMessage( 0 );
        return 0;
    }
    return DefWindowProc( hWnd, nMsg,
        wParam, lParam );
}

BOOL RegisterWnd( LPSTR pszClassName )
{
    WNDCLASSEX wce = { 0 };
    wce.cbSize        = sizeof( wce );
    wce.cbClsExtra    = 0;
    wce.cbWndExtra    = 0;
    wce.hbrBackground = HBRUSH(COLOR_WINDOW);
    wce.hCursor       = NULL;
    wce.hIcon          = NULL;
    wce.hIconSm       = NULL;
    wce.hInstance     = g_hInst;
    wce.lpfnWndProc   = WndProc;
    wce.lpszClassName = pszClassName;
    wce.lpszMenuName  = NULL;
    wce.style         = CS_VREDRAW|CS_HREDRAW;

    ATOM nAtom = RegisterClassEx( &wce );
    if( 0 == nAtom )
    {
        return FALSE;
    }
    return TRUE;
}

HWND CreateWnd( LPSTR pszClassName )
{
    HWND hWnd = CreateWindowEx( 0,
        pszClassName, "MyWnd", 
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, NULL, NULL, 
        g_hInst, 0 );
    return hWnd;
}

void DisplayWnd( HWND hWnd )
{
    ShowWindow( hWnd, SW_SHOW );
    UpdateWindow( hWnd );
}

void Message( )
{
    MSG msg = {0};
    while ( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
}

void NewConsole()  
{  
    /*产生控制台*/  
    AllocConsole();  
  
    /*获得控制台标准输出流句柄*/  
    g_hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);  
    CHAR szText[] = "Debug Message......:\n";  
    /*将szText 写到控制台*/  
    WriteConsole(g_hStdOut, szText, strlen(szText), NULL, NULL);  
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    NewConsole( );
    g_hInst = hInstance;
    RegisterWnd( "MYWND" );
    HWND hWnd = CreateWnd( "MYWND" );
    DisplayWnd( hWnd );
    Message( );
    return 0;
}

二 菜单
  1 菜单基础
    菜单 - 每一个菜单会有一个HMENU句柄
    菜单项 - 每一个菜单项会有一个ID号,能够依据这个ID运行不同的操作
  2 菜单的使用
    2.1 菜单创建
      2.1.1 CreateMenu - MENU 菜单
      2.1.2 CreatePopupMenu - POPUPMENU 弹出式菜单
      2.1.3 AppenedMenu - 添加菜单项

技术分享
  BOOL AppendMenu(
  HMENU hMenu, //菜单句柄
  UINT uFlags, //菜单项标示
  UINT uIDNewItem, //菜单项的ID或者子菜单句柄
  LPCTSTR lpNewItem ); //菜单项的名称
技术分享

    uFlags: 
      MF_STRING - lpNewItem是一个字符串
      MF_POPUP  - uIDNewItem是一个子菜单句柄
      MF_SEPARATOR - 添加分隔项
      MF_CHECKED/MF_UNCHECKED - 设置和取消菜单项的对勾
      MF_DISABLED/MF_ENABLE - 菜单项禁止和同意状态
   2.2 菜单的命令响应
     2.2.1 WM_COMMAND消息
       当用户点击菜单、button控件等时,系统会向窗体发送WM_COAMMD消息。


         WPARAM:HIWORD - 通知消息标识
                 LOWORD - 菜单项的ID号
         LPARAM:控件的句柄
     2.2.2 命令处理
        依据菜单项的ID号作对应处理。
        
   2.3 菜单项的状态
      2.3.1 WM_INITMENUPOPUP消息
        当用户点击菜单,显示弹出菜单之前,系统会向窗体发送WM_INITMENUPOPUP消息。
        WPARAM:是菜单句柄
        LPARAM:LOWORD - 菜单位置
                HIWORD - 是否是系统菜单
      2.3.2 命令处理
        依据WPARAM的菜单句柄,使用MenuAPI函数,改动菜单状态。


         CheckMenuItem - 选择
         EnableMenuItem - 同意和禁止
         SetMenuItemInfo - 能够设置很多其它信息

/* File : winMenu.cpp  
 * Auth : sjin  
 * Date : 20140706  
 * Mail : 413977243@qq.com  
 */    
    
#include <Windows.h>    
#include <stdio.h>


HINSTANCE g_hInst   = NULL;
HANDLE    g_hStdOut = NULL;
BOOL      g_bCheckCut = FALSE;

void OnCreate( HWND hWnd, UINT nMsg,
    WPARAM wParam, LPARAM lParam )
{    //创建主菜单
    HMENU hMainMenu = CreateMenu( );
    //创建子菜单
    HMENU hFileMenu = CreatePopupMenu( );
    //添加菜单项 (&N) 添加快捷键ALT+N)
    AppendMenu( hFileMenu, MF_STRING|MF_CHECKED, 1001, "新建(&N)");
	/*添加切割线的标示*/
    AppendMenu( hFileMenu, MF_SEPARATOR, 0, NULL );
    AppendMenu( hFileMenu, MF_STRING, 1002, "退出(&X)");
    AppendMenu( hMainMenu, MF_STRING|MF_POPUP, 
        (UINT)hFileMenu, "文件(&F)");

    HMENU hEditMenu = CreatePopupMenu( );
    AppendMenu( hEditMenu, MF_STRING, 1003, "剪切(&T)" );
	/*添加切割线的标示*/
    AppendMenu( hEditMenu, MF_SEPARATOR, 0, NULL );
    AppendMenu( hEditMenu, MF_STRING, 1004, "拷贝(&C)" );
	/*添加切割线的标示*/
    AppendMenu( hEditMenu, MF_SEPARATOR, 0, NULL );
    AppendMenu( hEditMenu, MF_STRING, 1005, "粘贴(&P)" );
    AppendMenu( hMainMenu, MF_STRING|MF_POPUP, 
        (UINT)hEditMenu, "编辑(&E)");

    HMENU hHelpMenu = CreatePopupMenu( );
    AppendMenu( hHelpMenu, MF_STRING, 1006, "帮助(&H)" );
	/*添加切割线的标示*/
    AppendMenu( hHelpMenu, MF_SEPARATOR, 0, NULL );
    AppendMenu( hHelpMenu, MF_STRING, 1007, "关于(&A)" );
    AppendMenu( hMainMenu, MF_STRING|MF_POPUP, 
        (UINT)hHelpMenu, "帮助(&H)");
    //给窗体设置主菜单
    SetMenu( hWnd, hMainMenu );
}

void OnCommand( HWND hWnd, UINT nMsg, 
               WPARAM wParam, LPARAM lParam )
{
	/*wParam: HIWORD: 通知消息的标示
	 *        LOWORD:菜单项的ID
	 * lParam: 控件的句柄
	 *         对菜单来说这个为NULL
	 *         对其它控件(button等)为句柄
	 */
    UINT nID = LOWORD( wParam );
    CHAR szText[260] = {0};
    sprintf( szText, "OnCommand: %d\n",
        nID );
    WriteConsole( g_hStdOut, szText,
        strlen(szText), NULL, NULL );

	/*菜单项的处理*/
    switch( nID )
    {
    case 1002:/*退出*/
        PostQuitMessage( 0 );
        break;
    case 1003:
        g_bCheckCut = !g_bCheckCut;
        break;
    }
}

void OnInitMenuPopup( HWND hWnd, UINT nMsg,
    WPARAM wParam, LPARAM lParam )
{
    CHAR szText[260] = { 0 };
    sprintf( szText, 
        "OnInitMenuPopup: WPARAM=%08X, LPARAM=%08X\n", 
        wParam, lParam );
    WriteConsole( g_hStdOut, szText,
        strlen(szText), NULL, NULL );

    HMENU hMenu = (HMENU)wParam;
    if( TRUE == g_bCheckCut )
    {
		/*CheckMenuItem是一个API函数,功能是复选或撤消复选指定的菜单栏目*/
        CheckMenuItem( hMenu, 1003, 
            MF_CHECKED|MF_BYCOMMAND );
    }
    else
    {
        CheckMenuItem( hMenu, 1003, 
            MF_UNCHECKED|MF_BYCOMMAND );
    }
}

LRESULT CALLBACK WndProc( HWND hWnd,
                          UINT nMsg,
                          WPARAM wParam,
                          LPARAM lParam )
{
    switch( nMsg )
    {
    case WM_CREATE:
        OnCreate( hWnd, nMsg, wParam, lParam );
        break;

		/*用户点击菜单、button控件等时,系统会想窗体发送WM_COAMMD消息*/
    case WM_COMMAND:
        OnCommand( hWnd, nMsg, wParam, lParam );
        break;

		/*用户点击菜单,显示弹出菜单之前,系统会向窗体发送WM_INITMENUPOPUP消息
		 *用于更新菜单项的状态
		 */
    case WM_INITMENUPOPUP:
        OnInitMenuPopup( hWnd, nMsg, wParam, lParam );
        break;
    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;
    }
    return DefWindowProc( hWnd, nMsg,
        wParam, lParam );
}

BOOL RegisterWnd( LPSTR pszClassName )
{
    WNDCLASSEX wce = { 0 };
    wce.cbSize        = sizeof( wce );
    wce.cbClsExtra    = 0;
    wce.cbWndExtra    = 0;
    wce.hbrBackground = HBRUSH(COLOR_WINDOW);
    wce.hCursor       = NULL;
    wce.hIcon          = NULL;
    wce.hIconSm       = NULL;
    wce.hInstance     = g_hInst;
    wce.lpfnWndProc   = WndProc;
    wce.lpszClassName = pszClassName;
    wce.lpszMenuName  = NULL;
    wce.style         = CS_VREDRAW|CS_HREDRAW;

    ATOM nAtom = RegisterClassEx( &wce );
    if( 0 == nAtom )
    {
        return FALSE;
    }
    return TRUE;
}

HWND CreateWnd( LPSTR pszClassName )
{
    HWND hWnd = CreateWindowEx( 0,
        pszClassName, "MyWnd", 
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, NULL, NULL, 
        g_hInst, 0 );
    return hWnd;
}

void DisplayWnd( HWND hWnd )
{
    ShowWindow( hWnd, SW_SHOW );
    UpdateWindow( hWnd );
}

void Message( )
{
    MSG msg = {0};
    while ( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
}

void NewConsole( )
{
    AllocConsole( );
    g_hStdOut = 
        GetStdHandle( STD_OUTPUT_HANDLE );
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    NewConsole( );
    g_hInst = hInstance;
    RegisterWnd( "MYWND_MENU" );
    HWND hWnd = CreateWnd( "MYWND_MENU" );
    DisplayWnd( hWnd );
    Message( );
    return 0;
}

三 系统菜单

  1 运行系统提供的窗体命令。比如最大化、关闭等命令。本质上和普通菜单一样,所以我们也能够在程序中使用这个菜单
    
  2 系统菜单的使用
    2.1 获取系统菜单
       GetSystemMenu

 HMENU GetSystemMenu(
    HWND hWnd, //要获取的窗体句柄
  BOOL bRevert  //获取时重置标示
 );

    bRevert: TRUE 重置 FLASE 不重置
    当Revert为TRUE时。会将菜单又一次置成默认的状态,并返回菜单句柄。假设为FALSE,菜单项不重置,获取到当前系统菜单的状态。


    
    2.2 改动系统菜单,比如添加、删除
       2.2.1 AppednMenu
       2.2.2 InsertMenu 
         比AppednMenu添加了一个插入菜单项的位置或ID。
       2.2.3 删除菜单项

  BOOL RemoveMenu( //
    HMENU hMenu, //菜单句柄
    UINT uPosition,//菜单项的位置或ID
    UINT uFlags );//菜单项的位置或ID的标示。

    uFlags为MF_BYCOMMAND, uPosition为菜单ID
    uFlags为MF_BYPOSITION,uPosition为菜单位置

    2.3 系统菜单的命令响应
       系统菜单的命令响应。是在WM_SYSCOMMAND中。


       WPARAM - LOWORD(wParam)为添加的菜单的ID

技术分享
     int nID = LOWORD( wParam );
    switch( nID )
    {
    case 1001:
      //...
        break;
    }
技术分享

/* File : winMenu.cpp   
 * Auth : sjin   
 * Date : 20140706   
 * Mail : 413977243@qq.com   
 */      
      
#include <Windows.h>      
#include <stdio.h> 

HINSTANCE g_hInst   = NULL;
HANDLE    g_hStdOut = NULL;

void OnCreate( HWND hWnd, UINT nMsg, 
              WPARAM wParam, LPARAM lParam )
{    
	/* 获取系统菜单
	 * HMENU GetSystemMenu(
	 *    HWND hWnd, //要获取的窗体句柄
     *    BOOL bRevert  //获取时重置标示
     *   );
	 *   bRevert : TRUE时,菜单会重置为默认状态
	 *             FALSE: 菜单不重置获得当前系统的菜单状态
	 */
    HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
    /*删除菜单项
	 * BOOL RemoveMenu( //
	 *		 HMENU hMenu, //菜单句柄
     *       UINT uPosition,//菜单项的位置或ID
     *        UINT uFlags );//菜单项的位置或ID的标示
	 *   uFlags为MF_BYCOMMAND, uPosition为菜单ID
     *   uFlags为MF_BYPOSITION,uPosition为菜单位置
	 */
    RemoveMenu( hSysMenu, 0, MF_BYPOSITION );
    RemoveMenu( hSysMenu, 0, MF_BYPOSITION );
    RemoveMenu( hSysMenu, 0, MF_BYPOSITION );
    RemoveMenu( hSysMenu, 0, MF_BYPOSITION );
    RemoveMenu( hSysMenu, 0, MF_BYPOSITION );
    // 添加菜单项
    InsertMenu( hSysMenu, 0, MF_BYPOSITION|MF_STRING,
        1001, "測试1" );
    InsertMenu( hSysMenu, 1, MF_BYPOSITION|MF_STRING,
        1002, "測试2" );
}

void OnSysCommand( HWND hWnd, UINT nMsg,
                   WPARAM wParam, LPARAM lParam )
{
    CHAR szText[260] = { 0 };
    sprintf( szText,
        "OnSysCommand: WPARAM=%08X,LPARAM=%08X\n",
        wParam, lParam );
    WriteConsole( g_hStdOut, szText, 
        strlen(szText), NULL, NULL );

    int nID = LOWORD( wParam );
    switch( nID )
    {
    case 1001:
        MessageBox( NULL, "Hello 1001", "SysMenu", MB_CANCELTRYCONTINUE );
        break;
    case 1002:
        MessageBox( NULL, "Hello 1002",  "SysMenu", MB_OK );
        break;
	default:
		break;
    }
}

LRESULT CALLBACK WndProc( HWND   hWnd, 
                          UINT   nMsg,
                          WPARAM wParam,
                          LPARAM lParam )
{
    switch( nMsg )
    {
    case WM_CREATE:
        OnCreate( hWnd, nMsg, wParam, lParam );
        break;
    case WM_SYSCOMMAND:/*系统菜单命令响应*/
        OnSysCommand( hWnd, nMsg, wParam, lParam );
        break;
    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;
    }
    return DefWindowProc( hWnd, nMsg,
        wParam, lParam );
}

BOOL RegisterWnd( LPSTR pszClassName )
{
    WNDCLASSEX wce = { 0 };
    wce.cbSize        = sizeof( wce );
    wce.cbClsExtra    = 0;
    wce.cbWndExtra    = 0;
    wce.hbrBackground = HBRUSH(COLOR_WINDOW);
    wce.hCursor       = NULL;
    wce.hIcon         = NULL;
    wce.hIconSm       = NULL;
    wce.hInstance     = g_hInst;
    wce.lpfnWndProc   = WndProc;
    wce.lpszClassName = pszClassName;
    wce.lpszMenuName  = NULL;
    wce.style         = CS_HREDRAW|CS_VREDRAW;

    ATOM nAtom = RegisterClassEx( &wce );
    if( 0 ==  nAtom )
    {
        return FALSE;
    }

    return TRUE;
}

HWND CreateWnd( LPSTR pszClassName )
{
    HWND hWnd = CreateWindowEx( 0,
        pszClassName, "MyWnd", 
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, NULL, NULL, g_hInst,
        NULL );
    return hWnd;
}

void DisplayWnd( HWND hWnd )
{
    ShowWindow( hWnd, SW_SHOW );
    UpdateWindow( hWnd );
}

void Message( )
{
    MSG msg = { 0 };
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
}

void NewConsole( )
{
    AllocConsole( );
    g_hStdOut = 
        GetStdHandle( STD_OUTPUT_HANDLE );
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    NewConsole( );
    g_hInst = hInstance;
    RegisterWnd( "MYWND" );
    HWND hWnd = CreateWnd( "MYWND" );
    DisplayWnd( hWnd );
    Message( );
    return 0;
}


走进windows编程的世界-----消息处理函数(3)