ActiveX控件的MFC设计之旅 联系客服

发布时间 : 星期五 文章ActiveX控件的MFC设计之旅更新完毕开始阅读0008256ca98271fe910ef902

LPDISPATCH* ppDisp = GetObjectArray(&nObjects); for (ULONG i = 0; i < nObjects; i++) {

DISPID dwDispID;

LPCOLESTR lpOleStr = T2COLE(\

if (SUCCEEDED(ppDisp->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID))) {

PropDispDriver.AttachDispatch(ppDisp, FALSE); BYTE rgbParams[] = VTS_I4;

PropDispDriver.InvokeHelper(dwDispID, DISPATCH_PROPERTYGET, VT_BSTR, &str, rgbParams, lItem);

PropDispDriver.DetachDispatch(); } }

return str; }

COLORREF CToppPropPage::GetColor() {

long l = 0;

GetPropText(\ COLORREF cr = RGB(0, 0, 0);

::OleTranslateColor((OLE_COLOR)l, NULL, &cr); return cr; }

void CToppPropPage::SetColor(COLORREF cr) {

SetPropText(\}

long CToppPropPage::GetCount() {

long lcount = 0;

GetPropText(\ return lcount; }

4.添加按钮(\添加项目\响应函数

void CToppPropPage::OnButtonAdditem() {

// TODO: Add your control notification handler code here UpdateData();

AddItem(m_strItem); //m_strItem为编辑框关联的CString对象 //填充列表框 long lcount = 0;

GetPropText(\

m_list.ResetContent(); //m_list为列表框关联的CListBox对象 for(int i=0; i

m_list.AddString(GetItem(i)); } }

5.添加按钮(\设置颜色\响应函数来设置控件的Color属性 void CToppPropPage::OnButtonSetcolor() {

// TODO: Add your control notification handler code here CColorDialog dlg;

if(dlg.DoModal() == IDOK){

long lcolor = dlg.GetColor(); SetPropText(\

GetDlgItem(IDC_STATIC_COLOR)->Invalidate(); } }

6.添加WM_CTLCOLOR消息响应函数,在函数里获得控件的Color属性,并用该Color设置静态文本框的文本背景颜色

HBRUSH CToppPropPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {

HBRUSH hbr = COlePropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);

// TODO: Change any attributes of the DC here if(nCtlColor == CTLCOLOR_STATIC){ COLORREF cr = GetColor(); pDC->SetBkColor(cr); }

// TODO: Return a different brush if the default is not desired return hbr; }

7.OK了,编译,可以在ActiveX Control Container中测试了

在上一步中我们实际是通过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 \,应该不用说的吧) 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, 0); }

void CToppPropPage::SetColor(COLORREF cr) {

if(m_pctrl) m_pctrl->m_color = cr; }

long CToppPropPage::GetCount() {