ActiveX控件的MFC设计之旅-第7步 .
发布时间:2020-12-16 22:49:12 所属栏目:大数据 来源:网络整理
导读:在上一步中我们实际是通过IDispatch接口的Invoke方法来访问控件的属性和方法的,虽然有COleDispatchDriver和其它一些辅助函数,但还是有些繁杂,能不能直接得到控件对象的指针,这样就可以直接访问控件了,甚至于控件的内部变量了?答案是肯定了。 我们的控件
在上一步中我们实际是通过IDispatch接口的Invoke方法来访问控件的属性和方法的,虽然有COleDispatchDriver和其它一些辅助函数,但还是有些繁杂,能不能直接得到控件对象的指针,这样就可以直接访问控件了,甚至于控件的内部变量了?答案是肯定了。
我们的控件派生自COleControl,COleControl派生自CWnd,CWnd又派生自CCmdTarget,我们的IDispatch接口就是在CCmdTarget中实现的(其实应该是实现在COleDispatchImpl类中),实现的方法比较特殊,这里不细细分析了,有兴趣的朋友可以自己看看MFC源码或者网上搜搜资料,应该能知道的。 我们能从CCmdTarget中获得IDispatch接口指针(GetIDispatch函数),同样的,我们也能从IDispatch接口指针中反向导出CCmdTarget对象指针,用到的是CCmdTarget的静态成员函数 static CCmdTarget* FromIDispatch( LPDISPATCH lpDispatch ); 前面我们已经知道可以通过属性页的GetObjectArray来获得控件的IDispatch接口指针,而有了上面的FromIDispatch这个函数,我们又可以从IDispatch接口指针中来获得控件的指针了,那么问题就解决了。 另外,这里我们还用到COlePropertyPage的一个虚拟函数OnObjectsChanged,在控件变化(包括控件加载上和卸载掉时)时,都会调用到这个函数。(其实,并不是一定要用这个函数的,只是想介绍一下,就用上了) 还是用上一步中的例子topp 1.添加控件类指针为属性页类的成员变量(#include "ToppCtl.h",应该不用说的吧) CToppCtrl* m_pctrl; 2.添加获得控件类指针的函数CToppCtrl* GetCtrlPtr(); CToppCtrl* CToppPropPage::GetCtrlPtr() { ULONG ulObjects; LPDISPATCH* lpObjectArray = GetObjectArray( &ulObjects ); ASSERT( lpObjectArray != NULL ); LPDISPATCH lpdisp = NULL; if(ulObjects > 0){//在这个函数中,并不一定能保证就有控件. lpdisp = lpObjectArray[0];//这里省事了,就假设只有一个控件了 } CToppCtrl* pctrl = NULL; if(lpdisp){ pctrl = (CToppCtrl*)CCmdTarget::FromIDispatch(lpdisp); } return pctrl; } 3.重载OnObjectsChanged,设置m_pctrl(在其它地方,如OnInitDialog中设置也无所谓,甚至即用即获得也无所谓) void CToppPropPage::OnObjectsChanged() { ULONG ulObjects; LPDISPATCH* lpObjectArray = GetObjectArray( &ulObjects ); ASSERT( lpObjectArray != NULL ); LPDISPATCH lpctl = NULL; if(ulObjects > 0){//在这个函数中,并不一定能保证就有控件. lpctl = lpObjectArray[0];//这里省事了,就假设只有一个控件了 } if(lpctl){ m_pctrl = (CToppCtrl*)CCmdTarget::FromIDispatch(lpctl); } else{ m_pctrl = NULL; } } 3.修改上一步中的几个成员函数 BOOL CToppPropPage::AddItem(LPCTSTR lpszItem) { if(m_pctrl) m_pctrl->m_saItems.Add(lpszItem); return m_pctrl != NULL; } CString CToppPropPage::GetItem(long lItem) { if(m_pctrl) { if(lItem >= 0 && lItem < m_pctrl->m_saItems.GetSize()){ return m_pctrl->m_saItems[lItem]; } else{ return _T(""); } } else{ return _T(""); } } //在获得m_color时,是直接将m_color从protected拉到了public下的,可恶的MFC,再添加新的属性或方法时可能会重新再添加一个,会给你带来一个小小的麻烦。 COLORREF CToppPropPage::GetColor() { if(m_pctrl) return m_pctrl->TranslateColor(m_pctrl->m_color); return RGB(0,0); } void CToppPropPage::SetColor(COLORREF cr) { if(m_pctrl) m_pctrl->m_color = cr; } long CToppPropPage::GetCount() { if(m_pctrl) return m_pctrl->m_saItems.GetSize(); return 0; } 4.编译,新建一VB工程,在VB下测试,可以发现没有问题 5.在ActiveX Control Container下测试,咦,出问题了,没有反应,为什么? 根据最后给出的资料上中的意思,大致是因为容器聚合了控件的原因(呵呵,懒得去想了,有兴趣的自己思考吧) 6.为控件添加一只读属性long CtrlPtr long CToppCtrl::GetCtrlPtr() { // TODO: Add your property handler here return reinterpret_cast<long>(this); return 0; } 7.编译,在ClassWizard的Automation下,点击Add Class,然后选择 From a type library,找到编译时为控件生成的.tlb文件,这里应该是在/Debug目录下,选择这个topp.tlb,然后只选择其中的_DTopp,点确定,这样将生成一个_DTopp类,和我们上一步中的介绍比较一下,可以发现,其实就是派生自一个COleDispatchDriver类,也就是说,只是一个帮助我们调用控件属性和方法的类(也就是说,我们上一步中其实完全不用自己来编代码的,ClassWizard可以为我们生成一个方便的可操作的类:))。 8.修改属性页的GetCtrlPtr函数如下: CToppCtrl* CToppPropPage::GetCtrlPtr() { ULONG ulObjects; LPDISPATCH* lpObjectArray = GetObjectArray( &ulObjects ); ASSERT( lpObjectArray != NULL ); LPDISPATCH lpdisp = NULL; if(ulObjects > 0){//在这个函数中,并不一定能保证就有控件. lpdisp = lpObjectArray[0];//这里省事了,就假设只有一个控件了 } CToppCtrl* pctrl = NULL; if(lpdisp){ pctrl = (CToppCtrl*)CCmdTarget::FromIDispatch(lpdisp); if(!pctrl){ long ControlPointer; _DTopp control(lpdisp); // GetObjectArray() docs state must not release pointer. control.m_bAutoRelease = FALSE; ControlPointer = control.GetCtrlPtr(); pctrl = reinterpret_cast<CToppCtrl*>(ControlPointer); //这里其实可以简单用如下的方法调用,之所以用上面的方法,只是用来介绍而已 /* long p; GetPropText("CtrlPtr",&p); pctrl = reinterpret_cast<CToppCtrl*>(p); */ } } return pctrl; } 9.编译,在ActiveX Control Container中测试,OK! 注释:这里用ClassWizard导入了一个辅助类是用来帮助从IDispatch中获得控件的CtrlPtr属性值的,其实并不一定需要这个辅助类的,见CToppCtrl* CToppPropPage::GetCtrlPtr()函数中被注释掉的代码,之所以引入这个辅助类,也是介绍起见。 参考资料: http://support.microsoft.com/kb/205670/ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |