我对ole技术的了解源于com技术的学习,认识源于windows os上多年的编程,而深入理解却来之多年的痛苦摸索、反复的体会,水到渠成的感觉终于有了。
记得很久以前有个人加我qq,说想学mfc,问有什么办法。我告诉它,得花2、3年时间才能入门,他说算了还是不学。我不知道是不是害了他,或者过早断送了他学习C++的路。小的时候很盼望长大,可以赚钱自立;记得学习编程的时候很希望自己能够入门。这种希望都变成了现时,自己走过的路只有自己清楚。有人说java好,有人说linux下编程来钱,有人说钻研技术没钱途,这些道理我明白只是自己可能并没有那么大梦想,或许很小的梦想都能满足我。
对于我这个年龄的青年来说,ole技术真的很晦涩难懂,这并不是自夸。记得以前在公司的时候,有个boss对com很了解。我本身不太爱问别人技术细节问题,但是崇拜之情下我找了他:做控件的时候如何强制控制控件的尺寸。得到的答案是:具体你看看里面的代码。当时我没有弄明白,只是暂时放弃。第二次是在研一的时候,问一个高级工程师(30多岁),如何在控件里面获取当前是设计时还是运行时。答案是:我回去看看在告诉你。结果是杳无音讯。我曾一度放弃com知识的进一步学习有一年,只是因为身边少了一个导师(在后来遇到了),或许自己很笨。
不多说了,下面来看技术吧。
问题是这样的:开发环境里面一般都是支持activex控件插入的,比如vb编辑器、vc编辑器、office系列产品,在mfc里面有ole文档。
假设我们要做一个activex容器,支持activex的插入、设计时属性编程的话,恐怕就需要一个载体(窗口),首先使其成为容器,支持插入,然后要提供idispatch接口为控件获取环境属性提供支持。为什么呢?我们首先来看看ATL.CComControlBase.GetAmbientUserMode方法:
HRESULT GetAmbientUserMode(BOOL& bUserMode)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
CComVariant var;
HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_USERMODE, var);
ATLASSERT(var.vt == VT_BOOL || FAILED(hRes));
bUserMode = var.boolVal;
return hRes;
}
进一步:
HRESULT GetAmbientProperty(DISPID dispid, VARIANT& var)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
HRESULT hRes = E_FAIL;
if (m_spAmbientDispatch.p != NULL)
hRes = m_spAmbientDispatch.GetProperty(dispid, &var);
return hRes;
}
其中m_spAmbientDispatch的获取是在这里:
inline HRESULT CComControlBase::IOleObject_SetClientSite(IOleClientSite *pClientSite)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
ATLASSERT(pClientSite == NULL || m_spClientSite == NULL);
m_spClientSite = pClientSite;
m_spAmbientDispatch.Release();
if (m_spClientSite != NULL)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
m_spClientSite->QueryInterface(IID_IDispatch,
(void**) &m_spAmbientDispatch.p);
}
return S_OK;
}
也就是activex控件在放到自己窝里面的时候设置的。这样我们的容器就需要实现IDispatch以便控件查询环境属性。
// this for activex control AMBIENT query
STDMETHODIMP CActiveXCtrl::Invoke(
DISPID dispidMember, REFIID iid, LCID lcid,
WORD wFlags, DISPPARAMS* pdpParams, VARIANT* pvarResult,
EXCEPINFO* pExceptionInfo, UINT* piArgError)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
if(dispidMember == DISPID_AMBIENT_USERMODE)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
VariantClear(pvarResult);
pvarResult->vt = VT_BOOL;
pvarResult->boolVal = VARIANT_FALSE;
return S_OK;
}
return E_NOTIMPL;
}
这里只是简单的返回activex控件的用户模式为设计时。我有一个测试,代码如下:
HRESULT OnDraw(ATL_DRAWINFO& di)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
RECT& rc = *(RECT*)di.prcBounds;
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
BOOL bUserMode = FALSE;
HRESULT hr = GetAmbientUserMode(bUserMode);
if(bUserMode)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
LPCTSTR pszText = _T("ATL 3.0 : UserMode");
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
}
else
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
LPCTSTR pszText = _T("ATL 3.0 : DesignMode");
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
return S_OK;
}
运行效果如下:
![](http://www.cppblog.com/images/cppblog_com/wlwlxj/730/o_olecontainer_1.PNG)
微软有一个控件叫owc11.chartspace.11,在设计时支持数据选择,而运行时不支持,来看看运行效果:
![](http://www.cppblog.com/images/cppblog_com/wlwlxj/730/o_olecontainer_2.PNG)
posted on 2007-05-13 08:57
万连文 阅读(2551)
评论(2) 编辑 收藏 引用 所属分类:
ATL