26win32编程基础——VisualStdio2010资源文件创建对话框和消息断点的本质是什么?
先创建1个空的win32项目

然后在资源文件--->右键---->添加*.rc

添加完之后,解决方案会多出来2个文件

然后切换到“资源视图”-->右键---->添加资源----->Dialog

就会出来1个对话框

然后在“解决方案管理器”中添加一个cpp文件,作为入口函数。

#include <windows.h>
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
return 0;
}
基本框架就搭建好了。
然后按照之前学过的窗口创建过程创建对话框(对话框、按钮等凡事皆窗口):
//1、创建窗口类 //2、窗口类赋值 //3、注册窗口类 //4、创建窗口------>我们只需要做这一步 //5、显示窗口 //6、消息循环 //7、回调函数------>回调函数也需要写,其他的都是系统做好的
Dialog也是窗口,之前我们创建窗口的7步,系统为我们做了一些事情,我们可以直接从4创建对话框开始,使用:
INT_PTR DialogBox(
HINSTANCE hInstance, //属于哪个应用程序 LPCTSTR lpTemplate, //对话框模板 HWND hWndParent, //父窗口 DLGPROC lpDialogFunc //回调函数 );
因此
#include <windows.h>
#include "resource.h"
HINSTANCE hIns;
INT_PTR CALLBACK DialogProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam);//对话框回调函数的声明
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
//1、创建窗口类
//2、窗口类赋值
//3、注册窗口类
//4、创建窗口------------>需要我们做
//5、显示窗口
//6、消息循环
//7、回调函数------------>需要我们做
//Dialog也是窗口,之前我们创建窗口的7步,系统为我们做了一些事情,我们只需要做2步,可以直接创建对话框
hIns = hInstance;
DialogBox(hIns,MAKEINTRESOURCE(ID_DialogMain),NULL,DialogProc);
return 0;
}
//对话框的消息处理函数:处理了返回true,未处理返回false
//窗口的消息处理函数:处理了返回0,未处理使用默认的消息处理函数让系统处置
INT_PTR CALLBACK DialogProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam)
{
int idDialog = LOWORD(wParam);
switch(uMsg)
{
case WM_INITDIALOG :
return TRUE;
case WM_QUIT:
PostQuitMessage(0);
return TRUE;
case WM_COMMAND:
{
int idDialog = LOWORD(wParam);
switch(idDialog){
case IDC_BUTTON_OK:
{
HWND hUserEdit = GetDlgItem(hwndDlg,IDC_USER_EDIT);
HWND hPassEdit = GetDlgItem(hwndDlg,IDC_PASS_EDIT);
char User[20];
char Pass[20];
//GetDlgItemText(hwndDlg,IDC_USER_EDIT,User,20);
//GetDlgItemText(hwndDlg,IDC_PASS_EDIT,Pass,20);
GetWindowText(hUserEdit,User,20);
GetWindowText(hPassEdit,Pass,20);
if(strcmp(User,"123")==0 && strcmp(Pass,"456")==0)
{
MessageBox(0,"输入正确!\n","正确",0);
}else{
MessageBox(0,"输入的用户名或者密码错误\n","ERROR",0);
}
return 0;
}
case IDC_BUTTON_CANCEL:
MessageBox(0,"CANCEL","点击的",0);
return 0;
}
break;
}
}
return FALSE;
};
由于我们只需要:创建对话框和编写回调函数,那么我们如何定位到我们感兴趣的回调函数的代码位置呢?
问题一:
假如我们的DialogBox对话框上有100个按钮,我们如何找到“注册”按钮对应的处理方法的位置呢?
我们以我们上边的最简单的对话框函数为例,结合od把windows的整个消息处理过程说清楚:
DialogBox创建的对话框,其实内部调用的是DialogBoxParamA这个函数,
然后根据第4个参数,找到DialogBox的回调函数,但是如果对话框上的按钮太多了,我们不可能1个1个的去找,如何快速找到“确定”按钮对应的消息处理位置呢?

用消息断点,可以快速的找到感兴趣的按钮的对应处理方法:
1、先od加载对应程序
2、F9先运行起来,把相关的界面和按钮都显示出来
3、然后在菜单“W”中----->找到对应的控件

我们知道,如果直接使用系统提供的窗口类创建窗口(对话框、按钮),系统会自动为我们注册1个回调函数,然后系统的这个回调函数最终会调用我们自己编写的回调函数。

因此从上图我们可以知道,可以从系统回调函数找到我们想要的回调过程,系统提供的回调函数是:0x7650739D
4、我们先在系统的回调函数位置下断点,右键--->在回调函数上设置消息断点


但是现在出现1个问题,我们怎么知道到底是鼠标按下去,还是鼠标松开产生的消息呢?
小技巧pis:测试一下,打开程序,然后对着按钮长按不松,如果是按下产生的消息,那么就会有反应,如果定义的是松开,那么程序就不会有反应(提示错误)
然后再松开,如果有反应(弹出提示),那么就能知道到底是WM_LBUTTONDOWN还是WM_LBUTTONUP

下完消息断点,然后输入直接点击“确定”;

然后程序就会在0x7650739D断下来,

5、我们知道最终会从0x7650739D----------到------>“确定”的消息处理位置
1、笨方法,单步执行,肯定最终会到“确定”的消息处理位置
2、既然最终会执行到“确定”的消息处理位置,也就是最终回到.text代码段
我们下一步就在.text代码段下访问断点,当从0x7650739D执行到.text代码段的第一行代码的时候就会停下来。

下完内存访问断点之后,我们F9运行起来。

这个位置就很有可能就是我们要找的位置,我们看下[ESP+8]的位置应该是WM_COMMAND(0x111)

说明这个位置还不是我们要找到WM_COMMAND消息的位置,为什么?
//对话框的消息处理函数:处理了返回true,未处理返回false //窗口的消息处理函数:处理了返回0,未处理使用默认的消息处理函数让系统处置 INT_PTR CALLBACK DialogProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam)
我们现在段下来的位置,就是对话框的回调函数的位置:
回调函数是无时无刻被系统调用的,所以消息是一直有的,并不是我们按下按钮之后,当我们不按的时候,就没有消息了,当暂停的时候,还有别的消息传递过来。
我们先把代码段的消息访问断点删除掉,不然访问一下代码段就会停一下:

因此我们还需要完善我们的条件:

当是控件0x3E9(注册按钮的id),并且是WM_COMMAND的消息的时候,才是我们想要的消息处理函数,然后我们单步F8,就找到我们正确的消息处理位置了。

我们只有对前边的:消息循环和消息传递充分理解,才能知道每一步在od中为什么操作。
外边的很多文章在消息循环这一块,只是讲了怎么操作,
根本没有讲为什么这样做?
我们做的逻辑都是前边的基础,并不是瞎做的,只有基础打牢,才能对各个过程充分理解,这就是学习底层的魅力所在。

浙公网安备 33010602011771号