MFC Tooltip跨模块/线程编程时应该注意的两个地方

本文介绍了在MFC编程中,Tooltip在跨模块和线程使用时需要注意的两个关键点。一是CWnd::EnableTooltip方法依赖于线程状态中的CTooltipCtrl,当CStatic等控件在DLL中而被EXE调用时,可能导致Tooltip功能失效。解决方法是在DLL中创建一个切换模块并手动分发消息的函数。二是Module卸载时销毁Tooltip可能因线程不同导致错误,因为销毁操作发生在非创建线程中。避免在非创建线程启用Tooltip是防止此类错误的有效策略。

准备:

模块状态:Module State, MFC对应类型AFX_MODULE_STATE
线程状态:Thread State, MFC对应类型AFX_THREAD_STATE
模块线程状态:Module Thread State, MFC对应类型AFX_MODULE_THREAD_STATE

模块概念:
MFC Regular DLL       -> Module
MFC EXE                    -> Module
MFC Extension DLL    -> None (所属的Module为CDynamicLibrary所挂载的Module,可以是Regular Dll或MFC EXE)

一个Module State含有多个Thread State。每个Thread State以TLS(Thread Local Storage)的方式存储
MFC对象如CWnd, CGdiObject等绑定到了一个特定Module下的特定Thread.
因此不同Module或不同Thread的情况下,MFC对象不能互访.


Tooltip注意1:


CWnd::EnableTooltip方法依赖于Thread State存储的内部的CTooltipCtrl控件来实现。MFC在内部实现时,首先从消息队列取出消息,再调用AfxPreTranslateMessage函数,AfxPreTranslateMessage最后会把该消息传递给从子控件到父控件的所有CWnd类的PreTranslateMessage方法中。在这个树级调用的过程中,是直接从当前Thread State中来查找的CWnd对象。在这种情况下,如果带有Tooltip的CWnd并没有绑定到这个Thread State时,会出现问题。比如下面这个例子:
CStatic开启了Tooltip,但是CStatic在一个Regular Dll中实现。另一个MFC EXE主程序调用了这个CStatic,此时这个CStatic并未在EXE程序的Thread State中,最终会导致Tooltip功能不起作用。
解决方法: 在Regular DLL中导出一个函数,函数实现时先切换到当前模块,再调用AfxPreTranslateMessage函数手工分发消息。而在MFC EXE中的CWnd或者CWinThread类的重载函数PreTranslateMessage中需先调用Regular DLL的这个导出函数。


Tooltip注意2:


CWnd::EnableTooltip方法依赖于Thread State存储的内部的CTooltipCtrl控件来实现,当Module卸载时,会依次删除所有存在的Thread State(保存在内部的一个链表),而在删除Thread State时,会调用CTooltipCtrl::DestroyTooltipCtrl方法来清除CTooltipCtrl控件。这个流程会在一定情况下出错:启用了Tooltip的控件所在的线程与执行Module卸载的线程不相同。这是因为,DestroyTooltipCtrl会最终调用DestroyWindow来从Thread State中清除CWnd。如果他们的线程不同,那么DestroyWindow就会找不到这个CWnd,最终引发出错。
解决方法:避免在其它线程中启用Tooltip.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值