由于我没有系统的学过ATL,而公司做控件的地方又很多,为了保险起见,我还是选择了使用MFC来做控件,在这过程中我发现了MFC的好多奇怪的问题,在这里列出来,大家可以讨论一下。
一:MFC不能做WEB服务端控件
这个我是听一老外说的,我具体试了一下,在ASP中用CreateObject的时候,的确失败,不知道大家有没有用MFC成功做过WEB服务端控件的呢?
二:如果控件中有线程未结束,则在关闭IE的时候有问题
我的调试条件是,在CXXXXCtrl类中开启一个无模式对话框,在无模式对话框中开启一个工作线程,如果在CXXXXCtrl类中开启一个工作线程,问题是不是这样我就不能肯定了。
假如控件退出的时候,不结束工作线程的话,那么当控件在IE中运行的时候,它会把控件所在的IE窗口和上一个IE窗口一块儿关闭,但不报任何错误。按道理上,主线程结束,将会导致子线程结束,所以结不结束工作线程,效果应该是一样的,但结果却不一样。
注:工作线程中没有任何需要释放的资源。
三:关于在控件中开无模式对话框
这个问题花去了我一周的调试时间,问题是这样的:
我想在控件中开个无模式对话框好多人都做过,也不会有什么问题,可是,如果在无模式对话框中再开一个无模式对话框呢?为了说明问题方便,我把在CXXXXCtrl类中开启的无模式对话框称为Dialog1(Child属性),在Dialog1中开启的无模式对话框称为Dialog2(Popup属性),大家可以想像成Dialog2为一查找对话框。为了让问题表现出来,我们在Dialog2上做点手脚:
在Dialog2上放个Edit框,并关联一个CEdit型控制变量,完了后编译控件,然后将控件放到IE中运行,在关闭IE的时候,问题出来了,一堆非法操作,什么什么地址不能读等错误,大家可以试试。奇怪的是在Dialgo2上放个列表框,并关联CListCtrl类控制变量却没有问题。
这个问题总结起来就是,在Dialog1中创建Dialog2的时候,无法让Dialog1成为Dialog2的父窗口,于是在资源释放问题上造成错乱,试着用SetParent函数给Dialog2指定父窗口为Dialog1也不行。
解决办法:在Dialog1的OnDestroy函数中执行Dialog2.DestroyWindow();
如果在Dialog2中开启无模式对话框Dialog3,恐怕就更复杂了,我都没调试过。
四:在控件中使用另一自编写的控件,调用IsDialogMessage函数造成死循环
我的调试条件是,在CXXXXCtrl类中开启一个无模式对话框,在无模式对话框中放上一个自写的MFC控件,
并为其关联控制型变量。假定无模式对话框为pDialog1(Child属性),在CXXXXCtrl类的PreTranslateMessage函数中写上如下代码:
return ::IsWindow(pDialog1->m_hWnd) && pDialog1->IsDialogMessage(pMsg) || COleControl::PreTranslateMessage(pMsg);
结果会怎么样呢?请这样调试:
在IE中运行控件,完全远行起来后,最小化IE,再还原IE,此时随便按键盘上某一个键,则CPU使用占百分之百,只能强行关闭IE这个问题我调试了好久,最后发现是pDialog1->IsDialogMessage(pMsg)调用进入了死循环!这个问题的解决办法你想都想不到,如下:
把pDialog1->IsDialogMessage(pMsg)改成::IsDialogMessage(pDialog1->m_hWnd, pMsg)即可。
pDialog1->IsDialogMessage(pMsg)和::IsDialogMessage(pDialog1->m_hWnd, pMsg)据说效果是一样的,我也认为一样,可是实际上,他们并不一样,这个问题怎么产生的我到现在还不明白!
注:我上面提到在无模式对话框上放置一个自写的MFC控件,虽然这个控件是我写的,但我可以保证这个控件不会有问题,我的自信来自下面的事实:
用VC6.0向导完全按默认生成一个MFC控件,不写任何一行程序即编译程序,然后用这个控件来做实验,效果一样!当然,如果不放置自写的MFC控件,上面的问题不会发生,这个我是调试过的。
注:上面的问题,除了第一个,其它的在应用程序中(比如添加到对话框上而不是在IE中)使用则完全没有问题。