我對ole技術的了解源于com技術的學習,認識源于windows os上多年的編程,而深入理解卻來之多年的痛苦摸索、反復的體會,水到渠成的感覺終于有了。
記得很久以前有個人加我qq,說想學mfc,問有什么辦法。我告訴它,得花2、3年時間才能入門,他說算了還是不學。我不知道是不是害了他,或者過早斷送了他學習C++的路。小的時候很盼望長大,可以賺錢自立;記得學習編程的時候很希望自己能夠入門。這種希望都變成了現時,自己走過的路只有自己清楚。有人說java好,有人說linux下編程來錢,有人說鉆研技術沒錢途,這些道理我明白只是自己可能并沒有那么大夢想,或許很小的夢想都能滿足我。
對于我這個年齡的青年來說,ole技術真的很晦澀難懂,這并不是自夸。記得以前在公司的時候,有個boss對com很了解。我本身不太愛問別人技術細節(jié)問題,但是崇拜之情下我找了他:做控件的時候如何強制控制控件的尺寸。得到的答案是:具體你看看里面的代碼。當時我沒有弄明白,只是暫時放棄。第二次是在研一的時候,問一個高級工程師(30多歲),如何在控件里面獲取當前是設計時還是運行時。答案是:我回去看看在告訴你。結果是杳無音訊。我曾一度放棄com知識的進一步學習有一年,只是因為身邊少了一個導師(在后來遇到了),或許自己很笨。
不多說了,下面來看技術吧。
問題是這樣的:開發(fā)環(huán)境里面一般都是支持activex控件插入的,比如vb編輯器、vc編輯器、office系列產品,在mfc里面有ole文檔。
假設我們要做一個activex容器,支持activex的插入、設計時屬性編程的話,恐怕就需要一個載體(窗口),首先使其成為容器,支持插入,然后要提供idispatch接口為控件獲取環(huán)境屬性提供支持。為什么呢?我們首先來看看ATL.CComControlBase.GetAmbientUserMode方法:
HRESULT GetAmbientUserMode(BOOL& bUserMode)

{
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)

{
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)


{
ATLASSERT(pClientSite == NULL || m_spClientSite == NULL);
m_spClientSite = pClientSite;
m_spAmbientDispatch.Release();
if (m_spClientSite != NULL)

{
m_spClientSite->QueryInterface(IID_IDispatch,
(void**) &m_spAmbientDispatch.p);
}
return S_OK;
}
也就是activex控件在放到自己窩里面的時候設置的。這樣我們的容器就需要實現IDispatch以便控件查詢環(huán)境屬性。
// 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)


{
if(dispidMember == DISPID_AMBIENT_USERMODE)

{
VariantClear(pvarResult);
pvarResult->vt = VT_BOOL;
pvarResult->boolVal = VARIANT_FALSE;
return S_OK;
}
return E_NOTIMPL;
}
這里只是簡單的返回activex控件的用戶模式為設計時。我有一個測試,代碼如下:
HRESULT OnDraw(ATL_DRAWINFO& di)

{
RECT& rc = *(RECT*)di.prcBounds;
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);

SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
BOOL bUserMode = FALSE;
HRESULT hr = GetAmbientUserMode(bUserMode);
if(bUserMode)

{
LPCTSTR pszText = _T("ATL 3.0 : UserMode");

TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
}
else

{
LPCTSTR pszText = _T("ATL 3.0 : DesignMode");
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
}

return S_OK;
}
運行效果如下:

微軟有一個控件叫owc11.chartspace.11,在設計時支持數據選擇,而運行時不支持,來看看運行效果:

posted on 2007-05-13 08:57
萬連文 閱讀(2580)
評論(2) 編輯 收藏 引用 所屬分類:
ATL