背景知识
VC向导里面有一个MFC ActiveX项,我们可以使用它来创建ActiveX控件,ActiveX技术是OLE技术的延伸,微软早期推出OLE技术不是非常成功,于是修改了名字以抹去人们对OLE的阴影。
ActiveX技术在现在应用非常广泛,它以COM思想为基础,以MFC技术实现,使得开发人员可以快速创建组件功能模块应用于Windows平台任何语言。
我们在使用ActiveX控件的时候(本文限于VC讨论)很简单,直接拖放控件或者通过CWnd::CreateControl创建。如果仅限于此,可以说能够很好的使用ActiveX控件,然而无法对控件实现定制。为什么要定制?我不想解释太多,因为有些东西意会而不能言传。用Spy看一下TT浏览器、遨游浏览器就可以知道它的内核就是IE的WebBrowser,它们的实现其实就是对WebBrowser的定制。如何才能进行定制?当然必须了解控件创建机制,了解应用与控件之间的模型,了解MFC背后为我们做了什么。
我以前一向很少使用ActiveX控件,原因很简单,我不了解内部技术,不是不会用,而是不能随心所欲的用。我一方面希望软件组件化,一方面又对ActiveX控件如此畏惧,自己内心其实都很矛盾。随着知识的积累,慢慢终于有能力去了解这些东西,我希望自己可以讲明白,也希望有人渴望了解,尽管是老技术。
牵扯到的类汇总
牵扯到ActiveX控件创建的有这些MFC类:COccManager、COleControlContainer、COleControlSite、COleControl。下面分别解释一下这些类:
COccManager:control container manager控件容器管理器,任何应用程序若要支持AxtiveX控件必须创建该对象,创建位置一般在×××App: InitInstance()函数里面AfxEnableControlContainer()。为容纳控件窗体创建COleControlContainer。
COleControlContainer:控件容器类,容纳ActiveX控件的窗体都创建该对象,用来创建COleControlSite对象以登录控件信息。
COleControlSite:COleControlContainer为每个ActiveX控件创建一个COleControlSite对象以登录控件信息。
COleControl:所有ActiveX控件从其派生。
对象创建流程分析
下面介绍这些对象的创建流程,通过分析可以清楚一个ActiveX控件创建细节:
控件容器管理对象位于应用程序级,如果应用支持ActiveX控件,那么会在应用初始化的时候创建一个管理器,MFC缺省实现:
AfxEnableControlContainer();
我们看下它的原型(AFXDISP.H ):
void AFX_CDECL AfxEnableControlContainer(COccManager* pOccManager=NULL);它的实现如下(OCCMGR.CPP ):
void AFX_CDECL AfxEnableControlContainer(COccManager* pOccManager)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
if (pOccManager == NULL)
afxOccManager = _afxOccManager.GetData();
else
afxOccManager = pOccManager;
}解释一下:如果传入NULL,MFC自动创建默认管理器,否则接管用户定义的管理器,这个地方是有意思的,我们可以在这个根部替换管理器从而替换容器对象的创建,进而定制站点。默认管理器依靠一个宏定义(OCCMGR.CPP )::
PROCESS_LOCAL(COccManager, _afxOccManager)在此不深入,有兴趣可以看看。
到这里有了控件管理器,这个应用就算支持ActiveX控件。下面来看看当ActiveX控件创建的时候发生了什么。
假设一个ActiveX控件创建采用如下形式(归根到底也应该如此)(OCCCONT.CPP ):
BOOL CWnd::CreateControl(REFCLSID clsid, LPCTSTR lpszWindowName, DWORD dwStyle,
const POINT* ppt, const SIZE* psize, CWnd* pParentWnd, UINT nID,
CFile* pPersist, BOOL bStorage, BSTR bstrLicKey)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
ASSERT(pParentWnd != NULL);
![](/Images/OutliningIndicators/InBlock.gif)
#ifdef _DEBUG
if (afxOccManager == NULL)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
TRACE0("Warning: AfxEnableControlContainer has not been called yet.\n");
TRACE0(">>> You should call it in your app's InitInstance function.\n");
}
#endif
![](/Images/OutliningIndicators/InBlock.gif)
if ((pParentWnd == NULL) || !pParentWnd->InitControlContainer())
return FALSE;
![](/Images/OutliningIndicators/InBlock.gif)
return pParentWnd->m_pCtrlCont->CreateControl(this, clsid, lpszWindowName,
dwStyle, ppt, psize, nID, pPersist, bStorage, bstrLicKey);
}看上面实现,由于已经有afxOccManager 了,继续向下看有
InitControlContainer()函数,控件父窗口初始化容器(OCCCONT.CPP ):
BOOL CWnd::InitControlContainer()
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
TRY
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (m_pCtrlCont == NULL)
m_pCtrlCont = afxOccManager->CreateContainer(this);
}
END_TRY
![](/Images/OutliningIndicators/InBlock.gif)
// Mark all ancestor windows as containing OLE controls.
if (m_pCtrlCont != NULL)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
CWnd* pWnd = this;
while ((pWnd != NULL) && !(pWnd->m_nFlags & WF_OLECTLCONTAINER))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
pWnd->m_nFlags |= WF_OLECTLCONTAINER;
pWnd = pWnd->GetParent();
if (! (GetWindowLong(pWnd->GetSafeHwnd(), GWL_STYLE) & WS_CHILD))
break;
}
}
![](/Images/OutliningIndicators/InBlock.gif)
return (m_pCtrlCont != NULL);
}这里看出加入没有容器对象,afxOccManager 则负责创建容器(每个窗体存在唯一容器对象),并且修改所有祖先窗口支持OLE风格。
接着父窗口的容器对象调用
CreateControl函数,看看它的实现过程(OCCSITE.CPP ):
BOOL COleControlContainer::CreateControl(CWnd* pWndCtrl, REFCLSID clsid,
LPCTSTR lpszWindowName, DWORD dwStyle, const POINT* ppt, const SIZE* psize,
UINT nID, CFile* pPersist, BOOL bStorage, BSTR bstrLicKey,
COleControlSite** ppNewSite)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
COleControlSite* pSite = NULL;
![](/Images/OutliningIndicators/InBlock.gif)
TRY
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
pSite = afxOccManager->CreateSite(this);
}
END_TRY
![](/Images/OutliningIndicators/InBlock.gif)
if (pSite == NULL)
return FALSE;
![](/Images/OutliningIndicators/InBlock.gif)
BOOL bCreated = SUCCEEDED( pSite->CreateControl(pWndCtrl, clsid,
lpszWindowName, dwStyle, ppt, psize, nID, pPersist, bStorage,
bstrLicKey ) );
![](/Images/OutliningIndicators/InBlock.gif)
if (bCreated)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ASSERT(pSite->m_hWnd != NULL);
m_siteMap.SetAt(pSite->m_hWnd, pSite);
if (ppNewSite != NULL)
*ppNewSite = pSite;
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
delete pSite;
}
![](/Images/OutliningIndicators/InBlock.gif)
return bCreated;
}afxOccManager负责为COleControlContainer创建COleControlSite对象,有COleControlSite对象创建具体ActiveX控件,由于COleControlSite::
CreateControl代码较长,此处不赘述,有兴趣可以自己看看,是ControlSite将ActiveX控件定位的过程。
为了便于大家理解,我根据自己理解绘制一个创建过程:
![](/images/cppblog_com/wlwlxj/730/o_ControlSite_1.jpg)
应用示例
上面介绍了创建流程,只谈这些你可能不明白到底有什么好处。这里示例还是我以前的一个例子:
使MFC变漂亮二:MFC与HTML交互示例
WebBrowser控件通过IDocHostUIHandler接口处理UI以及一些交互事件,我们可以定制自己的COleControlSite实现自定义行为,要创建自定义的COleControlSite对象就必须实现自定义的COccManager。因此例子中派生了两个类,分别实现定制COccManager、COleControlSite,当然你也可以创建自定义的COleControlContainer对象以在创建COleControlSite对象时为其提供某种服务。
不知道讲清楚没有,反正我是又糊涂了,^_^。难得糊涂!如果你想对Office有深入了解、希望应用集成VBA开发,这些知识都是必不可少。OLE技术还是ActiveX技术,我分不清,需要了解的太多,慢慢来。
posted on 2006-09-03 18:54
万连文 阅读(3907)
评论(4) 编辑 收藏 引用 所属分类:
MFC