win32按钮

1.按钮是什么
在win32窗口中,经常可以看到按钮,点击按钮可以触发各种事件;
 
创建按钮的函数:
void CreateButton(HWND hwnd)    //参数为父窗口句柄,按钮必须属于一个父窗口,因此该函数只要在父窗口创建完成即父窗口的CreateWindow函数调用完成之后就能调用;                                    
{                                    
    HWND hwndPushButton;                                
                                    
    hwndPushButton = CreateWindow (                                 
        TEXT("button"),                             
        TEXT("普通按钮"),                            
        //WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_DEFPUSHBUTTON,                            
        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_DEFPUSHBUTTON,                            
        10, 10,                            
        80, 20,                            
        hwnd,                             
        (HMENU)1001,        //子窗口ID                    
        hAppInstance,         //应用程序的句柄,也就是winmian中的参数hinstance                        
        NULL);                            
}
可以看到创建按钮和创建普通窗口一样,都是调用CreateWindow函数来实现;
创建窗口需要的步骤:1、创建窗口类;2、注册窗口类;3、创建窗口;
创建按钮直接CreateWindow,省去了前两步;
 
总结:
    按钮本质上就是一个窗口;
    按钮是系统定义好的窗口,创建按钮时只需在CreateWindow的第一个参数也就是窗口类名设为TEXT("button")即可;
 
单选框和多选框也是按钮;
不过是调用CreateWindow时传入的窗口外观样式不同而已;
按钮的窗口外观样式可以在msdn文档中查得到;
hwndCheckBox = CreateWindow (                             
    TEXT("button"),                         
    TEXT("复选框"),                        
    //WS_CHILD | WS_VISIBLE | BS_CHECKBOX | BS_AUTOCHECKBOX,                        
    WS_CHILD | WS_VISIBLE | BS_CHECKBOX |BS_AUTOCHECKBOX ,                        
    10, 40,                        
    80, 20,                        
    hwnd,                         
    (HMENU)1002,        //子窗口ID                
    hAppInstance,                         
    NULL);                        
                            
hwndRadio = CreateWindow (                             
    TEXT("button"),                         
    TEXT("单选按钮"),                        
    //WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON | BS_AUTORADIOBUTTON,                        
    WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON  ,                        
    10, 70,                        
    80, 20,                        
    hwnd,                         
    (HMENU)1003,        //子窗口ID                
    hAppInstance,                         
    NULL);     

 

子窗口id:
    在winmain中创建的窗口CreateWindow函数的倒数第三个参数为菜单句柄;
    菜单句柄的作用是给窗口添加菜单;
    如果是子窗口,则该参数表示子窗口id,用来在程序中唯一标识该窗口;
    将一个整数强转为HMENU类型来传入;
 
2.按钮事件的处理
1)关于按钮消息处理的原理
按钮本质上是一个窗口;
窗口通过注册的WNDCLASS结构中回调函数来处理事件;
按钮用来点击触发一些事件,就是通过回调函数来实现的;
按钮是系统创建的窗口,其回调函数也是系统创建的,因此并不需要给它提供回调函数;
 
按钮的WNDCLASS不是我们定义的,是系统预定义好的。
如果我们想知道,系统预定义的WNDCLASS都包含什么样的信息怎么做?                                        
TCHAR szBuffer[0x20];                    
GetClassName(hwndPushButton,szBuffer,0x20);     //获取wndclass结构的类名;参数:1.目标按钮的句柄、2.存结果的缓冲区、3.缓冲区字节数               
                    
WNDCLASS wc;                    
GetClassInfo(hAppInstance,szBuffer,&wc);         //这个函数可以获取wndclass结构的所有属性; 参数:1.应用程序句柄、2.目标wndclass结构的类名,用上一个函数获取、3.存结果的缓冲区                   
OutputDebugStringF("-->%s\n",wc.lpszClassName);                    
OutputDebugStringF("-->%x\n",wc.lpfnWndProc);        

 

2)按钮消息处理机制
按钮是一种特殊的窗体,并不需要提供单独的窗口回调函数.                            
当按钮有事件产生时,会给父窗口消息处理程序发送一个WM_COMMAND消息    
 
也就是说当点击按钮时:
    因为点击的是按钮这个窗口,会触发按钮的回调函数,也就是系统提供的WinProc;
    系统回调函数处理该消息的方式为:将点击事件转换为WM_COMMAND消息;
    父窗口的接收到WM_COMMAND消息后,调用父窗口回调函数来处理;
 
如果有多个按钮,父窗口的回调函数在处理WM_COMMAND消息时,需要区分到底是哪个按钮被点击;
WM_COMMAND消息会在消息附加信息wParam的低2字节中带上按钮的Id;
按钮的id用来唯一标识程序中的按钮,为按钮创建时的createwindow函数的倒数第三个参数;
WM_COMMAND消息处理:
case WM_COMMAND:                                
{                                
    switch(LOWORD(wParam))                            
    {                            
        case 1001:                        
            MessageBox(hwnd,"Hello Button 1","Demo",MB_OK);                    
            return 0;                    
        case 1002:                        
            MessageBox(hwnd,"Hello Button 2","Demo",MB_OK);                    
            return 0;                    
        case 1003:                        
            MessageBox(hwnd,"Hello Button 3","Demo",MB_OK);                    
            return 0;                    
    }                            
    return DefWindowProc(hwnd,uMsg,wParam,lParam);                            
}  

                      

3)带按钮的窗口程序实例
代码:
#include<stdio.h>
#include<windows.h>
#include "windebug.h"
 
 
HINSTANCE hAppInstance;    //应用程序句柄,因为要使用的地方太多需要定义成全局变量;在winmain函数中给它赋值
 
 
//创建按钮
void CreateButton(HWND hwnd)                                    
{                                    
    HWND hwndPushButton;                                
    HWND hwndCheckBox;                                
    HWND hwndRadio;                                
                                    
    hwndPushButton = CreateWindow (                                 
        TEXT("button"),                             
        TEXT("普通按钮"),                            
        //WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_DEFPUSHBUTTON,                            
        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_DEFPUSHBUTTON,                            
        10, 10,                            
        80, 20,                            
        hwnd,                             
        (HMENU)1001,        //子窗口ID                    
        hAppInstance,         //应用程序的句柄,                        
        NULL);                            
                                    
    hwndCheckBox = CreateWindow (                                 
        TEXT("button"),                             
        TEXT("复选框"),                            
        //WS_CHILD | WS_VISIBLE | BS_CHECKBOX | BS_AUTOCHECKBOX,                            
        WS_CHILD | WS_VISIBLE | BS_CHECKBOX |BS_AUTOCHECKBOX ,                            
        10, 40,                            
        80, 20,                            
        hwnd,                             
        (HMENU)1002,        //子窗口ID                    
        hAppInstance,                             
        NULL);                            
                                    
    hwndRadio = CreateWindow (                                 
        TEXT("button"),                             
        TEXT("单选按钮"),                            
        //WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON | BS_AUTORADIOBUTTON,                            
        WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON  ,                            
        10, 70,                            
        80, 20,                            
        hwnd,                             
        (HMENU)1003,        //子窗口ID                    
        hAppInstance,                             
        NULL);                            
}                                     
 
 
//声明回调函数
LRESULT CALLBACK WindowProc(                                      
    IN  HWND hwnd,          
    IN  UINT uMsg,          
    IN  WPARAM wParam,
    IN  LPARAM lParam
    
);
 
 
int CALLBACK WinMain(                        //CALLBACK是一个宏,表示__stdcall,也就是内平栈,win32所有api函数都是该调用约定
            HINSTANCE hInstance,
            HINSTANCE hPrevInstance,
            LPSTR lpCmdLine,
            int nCmdShow
            ){
    hAppInstance = hInstance;    //给全局变量赋值
 
 
    //1.告诉window要画一个什么样的窗口                                    
    TCHAR className[] = "My First Window";     //窗口的类名                                                                    
    // 创建窗口类的对象                                     
    WNDCLASS wndclass = {0};                        //一定要先将所有值赋值,否则RegisterClass函数无法起作用;            
    wndclass.hbrBackground = (HBRUSH)COLOR_MENU;                        //窗口的背景色            
    wndclass.lpfnWndProc =  WindowProc;                        //窗口过程函数            
    wndclass.lpszClassName = className;                        //窗口类的名字            
    wndclass.hInstance = hInstance;                        //定义窗口类的应用程序的实例句柄            
 
 
    //2.注册窗口类
    RegisterClass(&wndclass);          
 
 
    //3.创建窗口类
    HWND hwnd = CreateWindow(                              
        className,                //类名,可以用自己定义的窗口My First Window,也可用系统定义好的窗口例如按钮button        
        TEXT("我的第一个窗口"),                //窗口标题        
        WS_OVERLAPPEDWINDOW,                //窗口外观样式         
        10,                //相对于父窗口的X坐标        
        10,                //相对于父窗口的Y坐标        
        600,                //窗口的宽度          
        300,                //窗口的高度          
        NULL,                //父窗口句柄,为NULL          
        NULL,                //菜单句柄,为NULL          
        hInstance,                //当前应用程序的句柄          
        NULL);                //附加数据一般为NULL        
                                
    if(hwnd == NULL)                    //是否创建成功          
        return 0;      
    
    CreateButton(hwnd);        //创建按钮,需要在父窗口创建成功后调用
 
 
    //4.显示窗口
    ShowWindow(hwnd, SW_SHOW);          
 
 
    //5.消息循环
    MSG msg;              
    while(GetMessage(&msg, NULL, 0, 0))              
    {              
        TranslateMessage(&msg);          
        DispatchMessage(&msg);          
    }      
    return 0;
}
                                    
        
//6.回调函数,由操作系统来调用
/*                    
窗口消息处理程序 窗口回调函数:                    
                    
1、窗口回调函数处理过的消息,必须传回0.                    
                    
2、窗口回调不处理的消息,由DefWindowProc来处理.                    
*/                    
 
 
LRESULT CALLBACK WindowProc(                                      
                            IN  HWND hwnd,          
                            IN  UINT uMsg,          
                            IN  WPARAM wParam,          
                            IN  LPARAM lParam          
                            )          
{      
    switch(uMsg)                                
    {    
        //窗口消息                            
    case WM_CREATE:                                 
        {            
            DbgPrintf("WM_CREATE %d %d\n",wParam,lParam);                        
            CREATESTRUCT* createst = (CREATESTRUCT*)lParam;                        
            DbgPrintf("CREATESTRUCT %s\n",createst->lpszClass);                        
                                        
            return 0;                        
        }                            
    case WM_MOVE:                                
        {                            
            DbgPrintf("WM_MOVE %d %d\n",wParam,lParam);                        
            POINTS points = MAKEPOINTS(lParam);                        
            DbgPrintf("X Y %d %d\n",points.x,points.y);                        
                                    
            return 0;                        
        }                            
    case WM_SIZE:                                
        {                            
            DbgPrintf("WM_SIZE %d %d\n",wParam,lParam);                        
            int newWidth  = (int)(short) LOWORD(lParam);                            
            int newHeight  = (int)(short) HIWORD(lParam);                           
            DbgPrintf("WM_SIZE %d %d\n",newWidth,newHeight);                        
                                    
            return 0;                        
        }                            
    case WM_DESTROY:                                
        {                            
            DbgPrintf("WM_DESTROY %d %d\n",wParam,lParam);                        
            PostQuitMessage(0);                        
                                    
            return 0;                        
        }                            
        //键盘消息                            
    case WM_KEYUP:                                
        {                            
            DbgPrintf("WM_KEYUP %d %d\n",wParam,lParam);                        
                                    
            return 0;                        
        }                            
    case WM_KEYDOWN:                                
        {                            
            DbgPrintf("WM_KEYDOWN %d %d\n",wParam,lParam);                        
                                    
            return 0;                        
        }                            
        //鼠标消息                            
    case WM_LBUTTONDOWN:                                
        {                            
            DbgPrintf("WM_LBUTTONDOWN %d %d\n",wParam,lParam);                        
            POINTS points = MAKEPOINTS(lParam);                        
            DbgPrintf("WM_LBUTTONDOWN %d %d\n",points.x,points.y);                        
                                    
            return 0;                        
        }
        //按钮消息
    case WM_COMMAND:                                
        {                                
            switch(LOWORD(wParam))                            
            {                            
                case 1001:                        
                    MessageBox(hwnd,"Hello Button 1","Demo",MB_OK);                    
                    return 0;                    
                case 1002:                        
                    MessageBox(hwnd,"Hello Button 2","Demo",MB_OK);                    
                    return 0;                    
                case 1003:                        
                    MessageBox(hwnd,"Hello Button 3","Demo",MB_OK);                    
                    return 0;                    
            }                            
            return DefWindowProc(hwnd,uMsg,wParam,lParam);                            
        }
    }                                
    return DefWindowProc(hwnd,uMsg,wParam,lParam);                                
}
窗口:
 
3.分析按钮的事件处理
对于有多个按钮的窗口,有时需要只分析一个按钮事件处理;
 
例如:自分析上图窗口中的普通按钮,单选按钮和复选按钮不分析;
首先要找到程序入口winmain;
然后找回调函数,在回调函数开始处下断点;
因为回调函数可能需要处理很多消息,需要筛选按钮事件的消息WM_COMMAND;
也就是给断点添加条件;
条件为消息类型为WM_COMMAND,并且wParam所带的窗口id为普通按钮的id;
断点处回调函数的堆栈:
 
然后确定普通按钮的id:
    在od中点W可以查看子窗口信息
 
然后确定断点条件:
 
 
 
 
 
posted @ 2019-12-12 16:28  L丶银甲闪闪  阅读(1872)  评论(0编辑  收藏  举报