惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog
V
Vulnerabilities – Threatpost
Apple Machine Learning Research
Apple Machine Learning Research
V
V2EX
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
Latest news
Latest news
博客园 - 三生石上(FineUI控件)
美团技术团队
aimingoo的专栏
aimingoo的专栏
Google Online Security Blog
Google Online Security Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
T
Threatpost
Y
Y Combinator Blog
T
Tailwind CSS Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
A
Arctic Wolf
C
Cyber Attacks, Cyber Crime and Cyber Security
小众软件
小众软件
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Tenable Blog
W
WeLiveSecurity
L
LINUX DO - 热门话题
D
Docker
Cyberwarzone
Cyberwarzone
量子位
A
About on SuperTechFans
The Last Watchdog
The Last Watchdog
雷峰网
雷峰网
C
CERT Recently Published Vulnerability Notes
P
Palo Alto Networks Blog
The Hacker News
The Hacker News
Blog — PlanetScale
Blog — PlanetScale
P
Proofpoint News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
F
Full Disclosure
The Cloudflare Blog
T
The Blog of Author Tim Ferriss
T
The Exploit Database - CXSecurity.com
Engineering at Meta
Engineering at Meta
O
OpenAI News
Hacker News - Newest:
Hacker News - Newest: "LLM"
Scott Helme
Scott Helme
IT之家
IT之家
S
Secure Thoughts
MongoDB | Blog
MongoDB | Blog
L
Lohrmann on Cybersecurity
博客园 - 司徒正美
Google DeepMind News
Google DeepMind News

博客园 - 泉子

算法题:求一个序列S中所有包含T的子序列(distinct sub sequence) Django模板输出Dict所有Value的效率问题 笔记:LNK2001不代表链接器真的需要链接相关符号 Windows Restart Manager 重启管理器 advapi32.dll kernel32.dll 中的两套注册表API 使用GDI+保存带Alpha通道的图像(续) 使用GDI+保存带Alpha通道的图像 为什么不能将ptr_fun(operator delete)传递给For_Each 两个数之间的最短路径问题 C/C++函数中局部对象的构造与析构时机 四年记——身在中小企业 C++ Const总结 [转载]怎样用VB编写.DLL动态链接库文件 Visual Studio 6.0编译PWLib1.12总结 在Windows上编译PWLib 金山词霸没落了么? SendInput模拟键盘输入的问题 数组变量在取地址时回归:不再是指针 创建用于非Visual C++工具的DLL——VB调用C++ DLL为何必须使用def文件 - 泉子
窗口销毁的相关函数与消息,ActiveX控件的销毁
泉子 · 2012-02-07 · via 博客园 - 泉子

DestroyWindow函数

DestroyWindow销毁窗口的正牌函数。

DestroyWindows的MSDN说明如下:

The DestroyWindow function destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).

If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.

DestroyWindow also destroys modeless dialog boxes created by the CreateDialog function.

A thread cannot use DestroyWindow to destroy a window created by a different thread.

If the window being destroyed is a child window that does not have the WS_EX_NOPARENTNOTIFY style, a WM_PARENTNOTIFY message is sent to the parent.

DestroyWindow的处理过程总结要点如下:
1. 向父窗口发送WM_PARENTNOTIFY消息(仅当窗口具有WS_EX_NOPARENTNOTIFY样式);
2. 向窗口发送WM_DESTROY消息;
3. 使窗口转入非活动状态,移除键盘焦点;
4. 销毁子窗口(应该是通过递归调用DestroyWindow完成);
5. 销毁目标窗口资源:销毁菜单,清空线程的消息队列,销毁与窗口过程相关的定时器,解除窗口对剪贴板的拥有权,打断剪贴板器的查看链;
6. 向窗口发送WM_NCDESTROY消息;

上述条目大致从前往后执行(1、2、3的顺序不一定,5、6的顺序不一定)。依据是:
1. 根据WM_PARENTNOTIFY说明:销毁窗口时,系统在任何销毁窗口的操作执行前发送WM_PARENTNOTIFY至父窗口;
2. 根据WM_DESTROY说明:此消息先被发送至目标窗口,然后发送给目标窗口的所有子窗口,处理此消息时,可以假定所有子窗口还存在着;
3. 根据DestroyWindow说明:函数先销毁子窗口及所拥有的窗口,然后销毁目标窗口;
4. 根据WM_NCDESTROY说明:与WM_DESTROY相反的是,此消息在所有子窗口销毁之后发送; 没有去看汇编代码,只是根据各个MSDN说明来大致推测的,基本够用了吧。

根据MSDN说明,不能在非创建线程上调用DestroyWindow;若要在其它线程上关闭窗口,不可以直接调用DestroyWindow(错误"拒绝访问"),也不可以只发送WM_DESTROY,因为DestroyWindow才能完整的关闭窗口,WM_DESTROY消息只是关闭流程的一部分,甚至是最"无用"的一部分--WM_DESTROY只是用户响应的接口,而真正清理窗口的工作由DestroyWindow的其它部分完成。
要在其它线程上关闭窗口,可以向窗口发送WM_CLOSE消息,若窗口过程未在WM_CLOSE的处理中取消关闭操作,则DefWindowProc会默认调用DestroyWindow(彼时自然是在窗口的创建线程上)。

WM_CLOSE消息

WM_CLOSE的MSDN说明如下:

An application can prompt the user for confirmation, prior to destroying a window, by processing the WM_CLOSE message and calling the
DestroyWindow function only if the user confirms the choice.

By default, the DefWindowProc function calls the DestroyWindow function to destroy the window.

WM_CLOSE消息提供取消关闭窗口操作的接口,也可以作为窗口关闭的关联处理的统一入口。点击窗口右上角的关闭按钮将导致窗口收到WM_CLOSE消息,一般情况下,菜单中的Exit项的处理代码中也应向窗口发送WM_CLOSE消息,这样可以使无论何种方式触发的窗口关闭操作,其程序流均会流入WM_CLOSE消息的处理过程。在WM_CLOSE中可以对程序状态进行确认,自动或由用户确认是否取消关闭操作。
与接下来的其它消息相比,WM_CLOSE的特殊之处在于它发生在销毁过程启动之前。用户处理完WM_CLOSE消息后,如未取消,则DefWindowProc将调用DestroyWindow来关闭窗口,一旦进入DestroyWindow,则关闭过程将不可逆转。

WM_DESTROY消息

WM_DESTROY的MSDN说明如下:

The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window procedure of the window being destroyed after the window is removed from the screen.

This message is sent first to the window being destroyed and then to the child windows (if any) as they are destroyed. During the processing of the message, it can be assumed that all child windows still exist.

A window receives this message through its WindowProc function.

If the window being destroyed is part of the clipboard viewer chain (set by calling the SetClipboardViewer function), the window must remove itself from the chain by processing the ChangeClipboardChain function before returning from the WM_DESTROY message.

最后一句值得注意,不过对剪贴板涉猎不多,暂且不究。

WM_PARENTNOTIFY消息

WM_PARENTNOTIFY的MSDN说明如下:

The WM_PARENTNOTIFY message is sent to the parent of a child window when the child window is created or destroyed, or when the user clicks a mouse button while the cursor is over the child window. When the child window is being created, the system sends WM_PARENTNOTIFY just before the CreateWindow or CreateWindowEx function that creates the window returns. When the child window is being destroyed, the system sends the message before any processing to destroy the window takes place.

A window receives this message through its WindowProc function.

WM_NCDESTROY消息

WM_NCDESTROY的MSDN说明如下:

The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY message. WM_DESTROY is used to free the allocated memory object associated with the window. The WM_NCDESTROY message is sent after the child windows have been destroyed. In contrast, WM_DESTROY is sent before the child windows are destroyed. A window receives this message through its WindowProc function. This message frees any memory internally allocated for the window.

关于WM_DESTROY与WM_NCDESTROY,从各种说明可以看出,一个大约充当关闭操作启动时的通知接口,一个大约充当关闭操作完成时的通知接口。这也是我认为在DestroyWindow的处理流程中,第6条在第5条之后的原因。
另外,说明中有个值得一提的地方在于:WM_DESTROY用于释放关联到(associated to)窗口的已分配内存对象,WM_NCDESTROY用于释放内部为窗口分配的(internally allocated for)内存。 可以想象,后者应当指窗口的内核数据,但前者则有各种可能,菜单资源?GDI资源?异或是子窗口资源?这个就不好说了。 而且,根据这两句话的表述,似乎这两个清理操作是在消息的处理过程中发生的,然而显然又不是由用户来完成的工作,那么就应当是在DefWindowProc中完成的了。为什么不直接拿到Destroywindow中来执行呢?

ActiveX控件的销毁

销毁控件的最好方法是销毁宿主窗口。可以通过调用 CWindow::DestroyWindow 或 DestroyWindow API 显式地进行销毁,或者让宿主窗口的父级窗口的毁坏导致其死亡,从而隐式地进行销毁。这些方法的任何一种都将安全地销毁寄宿的控件。请注意,CAxWindow 对象的毁坏"不会"导致基础"AtlAxWin7"窗口的毁坏。
来自:http://technet.microsoft.com/zh-cn/query/cc468138