kotlin中mainactivity无法直接调用xml中的控件_定位MFC中SDK用于创建窗口的API

dae7c2aa1a7522ee0b1d052a3860eab7.png

本文是i春秋论坛作家「flag0」表哥原创的一篇技术文章,关于定位MFC中SDK创建窗口API位置的相关内容,感兴趣的小伙伴快来学习吧。

SDK中用于创建窗口的API

在SDK中创建窗口的过程,我们可以将其称为为创建窗口6要素。其分别为:

1、设计窗口类;

2、创建窗口实例;

3、显示窗口;

4、更新窗口;

5、建立消息循环;

6、实现窗口过程函数。

其中对应的API为:

1、RegisterClass;

2、CreateWindow;

3、ShowWindow;

4、UpdateWindow;

5、GetMessage、TranslateMessage、DispatchMessage;

6、WindowProc、DefWindowProc。

在MFC中对其进行了封装,接下来我们通过一系列的操作来定位到MFC中对应的SDK窗口的创建过程。

MFC单文件工程

一、定位消息循环

创建完项目后,配置项目属性。

属性页->配置属性->高级->在静态库中使用MFC

将其默认的在共享 DLL 中使用 MFC改成在静态库中使用MFC,就可以进行MFC框架的调试了。

7f61711b9b8e5de50a1a87df027e63a4.png

消息循环,使用F10无法步过,会陷入到函数里面,所以可以采用一路F10,然后依次跟进循环里面的方法来进行。

按F10运行断到Main函数的位置。

1346f0b70c0962a4bc6df2ccf370325e.png

按F11跟进AfxWinMain函数中(此处如果不进行配置在静态库中使用MFC会进入到别的函数)。

f524c838213e1e789957d336d655eaa1.png

接下来一路F10,可以看到程序陷入了函数中。

17c44f0172e4290b1dd005e9acbe0ad0.png

下断点,重新运行,F11进入该函数。

a08d6cebef17644292040d5d29675303.png

接着F11进入CWinThread::Run( )

84e0e09cb062577793a7fac44c71ef37.png

可以看到for循环是一个死循环,接着一路F10,可以发现程序在do while语句之间一直循环。

cf62b1420da4dac7f90268b00376cf38.png

do while循环中有三个函数,我们进入PumpMessage( )函数进行查看:

fe49a766287d4b409063082b8e66b23e.png

再紧接着进入AfxInternalPumpMessage( )函数中

320c864b96cee9e18465dd688774d97a.png

可以看到该函数中存在处理消息的APIGetMessage、TranslateMessage、DispatchMessage,据此可以判定,其为消息循环部分。

二、定位窗口过程函数

窗口过程函数是用来处理消息的,可以在发送消息处,下断点,通过栈回溯,找到窗口回调函数。

在控件操作处下断点,然后运行,触发该操作。

这里我们选择的是关于窗口的确定按钮控件。

a64825783db9055cc0d8a04df41fef3f.png

点击关于窗口的确定按钮

9f1052af53ce4273d256b43616d09298.png

可以看到断在了下断点的位置,打开调用堆栈窗口从上往下依次分析。

8826728376572f6159fb4418ad0f4f13.png

窗口过程函数的参数为:

  • HWND hWnd
  • UINT Msg
  • WPARAM wParam
  • LPARAM lParam

从上到下依次进行分析,哪个调用函数符合。

最终定位到CALLBACK,其参数列表完全符合,可以确定其就是窗口过程函数。

f2b457d014324a96f016888e7ceb24e4.png

3、UpdateWindow && ShowWindow

MSDN对该API描述如下:如果窗口的更新区域不为空,则通过向窗口发送WM_PAINT消息来更新指定窗口的客户端区域。该函数直接向指定窗口的窗口过程发送WM_PAINT消息,绕过应用程序队列。如果更新区域为空,则不发送消息。

我们可以判断,其会发送WM_PAINT消息,所以我们寻找MFC中的绘制函数在绘制时会发送WM_PAINT消息,最终确定了OnDraw函数。

f4c02b95b6bdb0a05cdeba4db5d8e70b.png

在OnDraw函数内部下断点

894e5cf24a8b5bedace1d7f643067940.png

运行后查看调用堆栈

99c8b05750d821b95d06473f89c4cc8f.png

双击进入该函数即可看到UpdateWindow API

8561e44ab142085b0eaedc0554a5bd2d.png

再往上回溯一层

701d40897e6ae88451686fbb4ffec564.png

进入InitInstance( )可以看到ShowWindowAPI

91af9d0a930713eff04c6acbbdf3966a.png

UpdateWindow当有效区存在时会调用窗口过程函数,发送WM_PAINT消息。

关系链如下:

UpdateWindow->(发送WM_PAINT消息)->WndProc->(处理WM_PAINT消息)->OnDraw

因此可以通过栈回溯定位到UpdateWindow

4、CreateWindow

在返回之前,Create Window向窗口过程发送WM_CREATE消息。

因此在处理WM_CREATE处下断点,通过栈回溯可以定位到CreateWindow。

在MainFrm.cpp中的OnCreate函数处下断点。

b027d2176f9e1eafa385ebfd44e23f96.png

查看调用堆栈,进行分析。

c4c0cbf443fa8ef13f1ef6c9082782ea.png

可以看到其参数与CreateWindowAPI的参数列表完全吻合

6cc5ebd042e608329670b2bffa461519.png

可以判定其就是CreateWindowAPI

139975255ae28389fbbaeb9dd3a0b2e2.png

5、定位RegisterClass

通过CreateWindow的类名进行回溯RegisterClass

8de8ab126d40385f394406672e8279a2.png

查看调用堆栈中上一层的函数的调用。

df73ddcf22b3baa0283421ff2f46685c.png

可以看到其也来源于上层函数调用,再往上回溯一层。

97a950643869a8be45cba801b10f37f3.png

此时可以看到类名来源于GetIconWndClass函数,按F9下断点,F5继续运行到当前断点后F11跟进去。

a6f40ddcbfac5dfe181e00815f120e41.png

我们关注该函数的返回值,可以看到其有两个返回,排除返回为NULL的那个,在另一个返回处下断点,跟进。

bab8e75d39ec34dd4804b738177f1c47.png

我们同样关注该函数的返回,其有两个返回,从上到下依次进行分析,首先在GetClassInfo处下断点跟进。

562de24b647ba3581e20c85cb68a066e.png

按F11发现其并没有进入函数内部,继续关注另一个函数AfxRegisterClass,下断点跟进。

b7ca8a478df0a283249c4186297e2f70.png

在该函数内部可以发现RegisterClass的宏定义,跟进后确定其RegisterClassAPI的位置。

e1420f53d23868def882b11390cc38b1.png

以上我们依次找到了创建窗口的六要素的位置。

总结

1、RegisterClass通过CreateWindow回溯ClassName。

2、CreateWindow找到处理WM_CREATE消息处OnCreate,进行栈回溯。

3、UpdateWindow找到处理WM_PAINT消息处OnDraw处下断点进行栈回溯。

4、ShowWindow找到处理WM_PAINT消息处OnDraw处下断点进行栈回溯。

5、消息循环F10,然后依次跟进循环内部进行分析。

6、窗口过程函数在发送消息处,下断点,通过栈回溯,找到窗口回调函数。

以上就完成了MFC单文件工程中,SDK创建窗口API的定位。

以上是今天要分享的内容,大家看懂了吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值