ATLCTL.CPP

// This is a part of the Active Template Library. 
// Copyright (C) 1996-1997 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Active Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Active Template Library product.

#ifndef ATL_NO_NAMESPACE
namespace ATL
{
#endif

/////////////////////////////////////////////////////////////////////////////
// CComDispatchDriver support

HRESULT CComDispatchDriver::GetProperty(IDispatch* pDisp, DISPID dwDispID,
VARIANT* pVar)
{
ATLTRACE(_T("CPropertyHelper::GetProperty\n"));
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
return pDisp->Invoke(dwDispID, IID_NULL,
LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
&dispparamsNoArgs, pVar, NULL, NULL);
}

HRESULT CComDispatchDriver::PutProperty(IDispatch* pDisp, DISPID dwDispID,
VARIANT* pVar)
{
ATLTRACE(_T("CPropertyHelper::PutProperty\n"));
DISPPARAMS dispparams = {NULL, NULL, 1, 1};
dispparams.rgvarg = pVar;
DISPID dispidPut = DISPID_PROPERTYPUT;
dispparams.rgdispidNamedArgs = &dispidPut;

if (pVar->vt == VT_UNKNOWN || pVar->vt == VT_DISPATCH ||
(pVar->vt & VT_ARRAY) || (pVar->vt & VT_BYREF))
{
HRESULT hr = pDisp->Invoke(dwDispID, IID_NULL,
LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
&dispparams, NULL, NULL, NULL);
if (SUCCEEDED(hr))
return hr;
}

return pDisp->Invoke(dwDispID, IID_NULL,
LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
&dispparams, NULL, NULL, NULL);
}

//////////////////////////////////////////////////////////////////////////////
// CFirePropNotifyEvent

HRESULT CFirePropNotifyEvent::FireOnRequestEdit(IUnknown* pUnk, DISPID dispID)
{
CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> pCPC(pUnk);
if (!pCPC)
return S_OK;
CComPtr<IConnectionPoint> pCP;
pCPC->FindConnectionPoint(IID_IPropertyNotifySink, &pCP);
if (!pCP)
return S_OK;
CComPtr<IEnumConnections> pEnum;

if (FAILED(pCP->EnumConnections(&pEnum)))
return S_OK;
CONNECTDATA cd;
while (pEnum->Next(1, &cd, NULL) == S_OK)
{
if (cd.pUnk)
{
HRESULT hr = S_OK;
CComQIPtr<IPropertyNotifySink, &IID_IPropertyNotifySink> pSink(cd.pUnk);
if (pSink)
hr = pSink->OnRequestEdit(dispID);
cd.pUnk->Release();
if (hr == S_FALSE)
return S_FALSE;
}
}
return S_OK;
}

HRESULT CFirePropNotifyEvent::FireOnChanged(IUnknown* pUnk, DISPID dispID)
{
CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> pCPC(pUnk);
if (!pCPC)
return S_OK;
CComPtr<IConnectionPoint> pCP;
pCPC->FindConnectionPoint(IID_IPropertyNotifySink, &pCP);
if (!pCP)
return S_OK;
CComPtr<IEnumConnections> pEnum;

if (FAILED(pCP->EnumConnections(&pEnum)))
return S_OK;
CONNECTDATA cd;
while (pEnum->Next(1, &cd, NULL) == S_OK)
{
if (cd.pUnk)
{
CComQIPtr<IPropertyNotifySink, &IID_IPropertyNotifySink> pSink(cd.pUnk);
if (pSink)
pSink->OnChanged(dispID);
cd.pUnk->Release();
}
}
return S_OK;
}

/////////////////////////////////////////////////////////////////////////////
// Control support

HRESULT CComControlBase::IQuickActivate_QuickActivate(QACONTAINER *pQACont,
QACONTROL *pQACtrl)
{
_ASSERTE(pQACont != NULL);
_ASSERTE(pQACtrl != NULL);
_ASSERTE(pQACont->cbSize >= sizeof(QACONTAINER));
_ASSERTE(pQACtrl->cbSize >= sizeof(QACONTROL));

if (!pQACont || !pQACtrl)
return E_POINTER;

HRESULT hRes;
memset(pQACtrl, 0, sizeof(QACONTROL));
pQACtrl->cbSize = sizeof(QACONTROL);

// get all interfaces we are going to need
CComPtr<IOleObject> pOO;
ControlQueryInterface(IID_IOleObject, (void**)&pOO);
CComPtr<IViewObjectEx> pVOEX;
ControlQueryInterface(IID_IViewObjectEx, (void**)&pVOEX);
CComPtr<IPointerInactive> pPI;
ControlQueryInterface(IID_IPointerInactive, (void**)&pPI);
CComPtr<IProvideClassInfo2> pPCI;
ControlQueryInterface(IID_IProvideClassInfo2, (void**)&pPCI);

if (pOO == NULL || pVOEX == NULL)
return E_FAIL;

pOO->SetClientSite(pQACont->pClientSite);

if (pQACont->pAdviseSink != NULL)
{
ATLTRACE(_T("Setting up IOleObject Advise\n"));
pVOEX->SetAdvise(DVASPECT_CONTENT, 0, pQACont->pAdviseSink);
}

CComPtr<IConnectionPointContainer> pCPC;
ControlQueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);

if (pQACont->pPropertyNotifySink)
{
ATLTRACE(_T("Setting up PropNotify CP\n"));
CComPtr<IConnectionPoint> pCP;
if (pCPC != NULL)
{
hRes = pCPC->FindConnectionPoint(IID_IPropertyNotifySink, &pCP);
if (SUCCEEDED(hRes))
pCP->Advise(pQACont->pPropertyNotifySink, &pQACtrl->dwPropNotifyCookie);
}
}

if (pPCI)
{
GUID iidDefaultSrc;
if (SUCCEEDED(pPCI->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID,
&iidDefaultSrc)))
{
if (pQACont->pUnkEventSink)
{
ATLTRACE(_T("Setting up Default Out Going Interface\n"));
CComPtr<IConnectionPoint> pCP;
if (pCPC != NULL)
{
hRes = pCPC->FindConnectionPoint(iidDefaultSrc, &pCP);
if (SUCCEEDED(hRes))
pCP->Advise(pQACont->pUnkEventSink, &pQACtrl->dwEventCookie);
}
}
}
}
// give information to container
if (pOO != NULL)
pOO->GetMiscStatus(DVASPECT_CONTENT, &pQACtrl->dwMiscStatus);

if (pVOEX != NULL)
pVOEX->GetViewStatus(&pQACtrl->dwViewStatus);

if (pPI != NULL)
pPI->GetActivationPolicy(&pQACtrl->dwPointerActivationPolicy);
return S_OK;
}

HRESULT CComControlBase::IPersistPropertyBag_Load(LPPROPERTYBAG pPropBag,
LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap)
{
USES_CONVERSION;
CComPtr<IDispatch> pDispatch;
const IID* piidOld = NULL;
for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
{
if (pMap[i].szDesc == NULL)
continue;
CComVariant var;

if(pMap[i].piidDispatch != piidOld)
{
pDispatch.Release();
if(FAILED(ControlQueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
{
ATLTRACE(_T("Failed to get a dispatch pointer for property #%i\n"), i);
return E_FAIL;
}
piidOld = pMap[i].piidDispatch;
}

if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
{
ATLTRACE(_T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
return E_FAIL;
}

HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
if (FAILED(hr))
{
if (hr == E_INVALIDARG)
{
ATLTRACE(_T("Property %s not in Bag\n"), OLE2CT(pMap[i].szDesc));
}
else
{
// Many containers return different ERROR values for Member not found
ATLTRACE(_T("Error attempting to read Property %s from PropertyBag \n"), OLE2CT(pMap[i].szDesc));
}
continue;
}

if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
{
ATLTRACE(_T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
return E_FAIL;
}
}
return S_OK;

}

HRESULT CComControlBase::IPersistPropertyBag_Save(LPPROPERTYBAG pPropBag,
BOOL fClearDirty, BOOL /*fSaveAllProperties*/, ATL_PROPMAP_ENTRY* pMap)
{
if (pPropBag == NULL)
{
ATLTRACE(_T("PropBag pointer passed in was invalid\n"));
return E_POINTER;
}

CComPtr<IDispatch> pDispatch;
const IID* piidOld = NULL;
for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
{
if (pMap[i].szDesc == NULL)
continue;
CComVariant var;

if(pMap[i].piidDispatch != piidOld)
{
pDispatch.Release();
if(FAILED(ControlQueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
{
ATLTRACE(_T("Failed to get a dispatch pointer for property #%i\n"), i);
return E_FAIL;
}
piidOld = pMap[i].piidDispatch;
}

if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
{
ATLTRACE(_T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
return E_FAIL;
}

if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH)
{
if (var.punkVal == NULL)
{
ATLTRACE(_T("Warning skipping empty IUnknown in Save\n"));
continue;
}
}

HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
if (FAILED(hr))
return hr;
}
m_bRequiresSave = FALSE;
return S_OK;
}

HRESULT CComControlBase::ISpecifyPropertyPages_GetPages(CAUUID* pPages,
ATL_PROPMAP_ENTRY* pMap)
{
_ASSERTE(pMap != NULL);
int nCnt = 0;
// Get count of unique pages
for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
{
if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
nCnt++;
}
pPages->pElems = NULL;
pPages->pElems = (GUID*) CoTaskMemAlloc(sizeof(CLSID)*nCnt);
if (pPages->pElems == NULL)
return E_OUTOFMEMORY;
nCnt = 0;
for(i = 0; pMap[i].pclsidPropPage != NULL; i++)
{
if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
{
BOOL bMatch = FALSE;
for (int j=0;j<nCnt;j++)
{
if (InlineIsEqualGUID(*(pMap[i].pclsidPropPage), pPages->pElems[j]))
{
bMatch = TRUE;
break;
}
}
if (!bMatch)
pPages->pElems[nCnt++] = *pMap[i].pclsidPropPage;
}
}
pPages->cElems = nCnt;
return S_OK;
}

BOOL CComControlBase::SetControlFocus(BOOL bGrab)
{
if (m_bWndLess)
{
if (!m_bUIActive && bGrab)
if (FAILED(InPlaceActivate(OLEIVERB_UIACTIVATE)))
return FALSE;

return (m_spInPlaceSite->SetFocus(bGrab) == S_OK);
}
else
{
// we've got a window.
//
if (m_bInPlaceActive)
{
HWND hwnd = (bGrab) ? m_hWndCD : ::GetParent(m_hWndCD);
if (!m_bUIActive && bGrab)
return SUCCEEDED(InPlaceActivate(OLEIVERB_UIACTIVATE));
else
return (::SetFocus(hwnd) != NULL);
}
}
return FALSE;
}

HRESULT CComControlBase::DoVerbProperties(LPCRECT /* prcPosRect */, HWND hwndParent)
{
HRESULT hr = S_OK;
CComQIPtr <ISpecifyPropertyPages, &IID_ISpecifyPropertyPages> spPages;
CComQIPtr <IOleObject, &IID_IOleObject> spObj;
CComQIPtr <IOleControlSite, &IID_IOleControlSite> spSite(m_spClientSite);

if (spSite)
{
hr = spSite->ShowPropertyFrame();
if (SUCCEEDED(hr))
return hr;
}

CComPtr<IUnknown> pUnk;
ControlQueryInterface(IID_IUnknown, (void**)&pUnk);
_ASSERTE(pUnk != NULL);
CAUUID pages;
spPages = pUnk;
if (spPages)
{
spPages->GetPages(&pages);
spObj = pUnk;
if (spObj)
{
LPOLESTR szTitle = NULL;

spObj->GetUserType(USERCLASSTYPE_SHORT, &szTitle);

hr = OleCreatePropertyFrame(hwndParent, m_rcPos.top, m_rcPos.left, szTitle,
1, &pUnk.p, pages.cElems, pages.pElems, LOCALE_USER_DEFAULT, 0, 0);

CoTaskMemFree(szTitle);
}
else
{
hr = OLEOBJ_S_CANNOT_DOVERB_NOW;
}
}
else
{
hr = OLEOBJ_S_CANNOT_DOVERB_NOW;
}

return hr;
}

HRESULT CComControlBase::InPlaceActivate(LONG iVerb, const RECT* prcPosRect)
{
HRESULT hr;

if (m_spClientSite == NULL)
return S_OK;

CComPtr<IOleInPlaceObject> pIPO;
ControlQueryInterface(IID_IOleInPlaceObject, (void**)&pIPO);
_ASSERTE(pIPO != NULL);
if (prcPosRect != NULL)
pIPO->SetObjectRects(prcPosRect, prcPosRect);

if (!m_bNegotiatedWnd)
{
if (!m_bWindowOnly)
// Try for windowless site
hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSiteWindowless, (void **)&m_spInPlaceSite);

if (m_spInPlaceSite)
{
m_bInPlaceSiteEx = TRUE;
m_bWndLess = SUCCEEDED(m_spInPlaceSite->CanWindowlessActivate());
m_bWasOnceWindowless = TRUE;
}
else
{
m_spClientSite->QueryInterface(IID_IOleInPlaceSiteEx, (void **)&m_spInPlaceSite);
if (m_spInPlaceSite)
m_bInPlaceSiteEx = TRUE;
else
hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&m_spInPlaceSite);
}
}

_ASSERTE(m_spInPlaceSite);
if (!m_spInPlaceSite)
return E_FAIL;

m_bNegotiatedWnd = TRUE;

if (!m_bInPlaceActive)
{

BOOL bNoRedraw = FALSE;
if (m_bWndLess)
m_spInPlaceSite->OnInPlaceActivateEx(&bNoRedraw, ACTIVATE_WINDOWLESS);
else
{
if (m_bInPlaceSiteEx)
m_spInPlaceSite->OnInPlaceActivateEx(&bNoRedraw, 0);
else
{
HRESULT hr = m_spInPlaceSite->CanInPlaceActivate();
if (FAILED(hr))
return hr;
m_spInPlaceSite->OnInPlaceActivate();
}
}
}

m_bInPlaceActive = TRUE;

// get location in the parent window,
// as well as some information about the parent
//
OLEINPLACEFRAMEINFO frameInfo;
RECT rcPos, rcClip;
CComPtr<IOleInPlaceFrame> spInPlaceFrame;
CComPtr<IOleInPlaceUIWindow> spInPlaceUIWindow;
frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
HWND hwndParent;
if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK)
{
m_spInPlaceSite->GetWindowContext(&spInPlaceFrame,
&spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);

if (!m_bWndLess)
{
if (m_hWndCD)
{
ShowWindow(m_hWndCD, SW_SHOW);
SetFocus(m_hWndCD);
}
else
{
HWND h = CreateControlWindow(hwndParent, rcPos);
_ASSERTE(h == m_hWndCD);
}
}

pIPO->SetObjectRects(&rcPos, &rcClip);
}

CComPtr<IOleInPlaceActiveObject> spActiveObject;
ControlQueryInterface(IID_IOleInPlaceActiveObject, (void**)&spActiveObject);

// Gone active by now, take care of UIACTIVATE
if (DoesVerbUIActivate(iVerb))
{
if (!m_bUIActive)
{
m_bUIActive = TRUE;
hr = m_spInPlaceSite->OnUIActivate();
if (FAILED(hr))
return hr;

SetControlFocus(TRUE);
// set ourselves up in the host.
//
if (spActiveObject)
{
if (spInPlaceFrame)
spInPlaceFrame->SetActiveObject(spActiveObject, NULL);
if (spInPlaceUIWindow)
spInPlaceUIWindow->SetActiveObject(spActiveObject, NULL);
}

if (spInPlaceFrame)
spInPlaceFrame->SetBorderSpace(NULL);
if (spInPlaceUIWindow)
spInPlaceUIWindow->SetBorderSpace(NULL);
}
}

m_spClientSite->ShowObject();

return S_OK;
}

HRESULT CComControlBase::IPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap)
{
_ASSERTE(pMap != NULL);
HRESULT hr = S_OK;
DWORD dwVer;
hr = pStm->Read(&dwVer, sizeof(DWORD), NULL);
if (SUCCEEDED(hr) && dwVer <= _ATL_VER)
hr = pStm->Read(&m_sizeExtent, sizeof(m_sizeExtent), NULL);
if (FAILED(hr))
return hr;

CComPtr<IDispatch> pDispatch;
const IID* piidOld = NULL;
for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
{
if (pMap[i].szDesc == NULL)
continue;
CComVariant var;

HRESULT hr = var.ReadFromStream(pStm);
if (FAILED(hr))
break;

if(pMap[i].piidDispatch != piidOld)
{
if(FAILED(ControlQueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
{
ATLTRACE(_T("Failed to get a dispatch pointer for property #%i\n"), i);
hr = E_FAIL;
break;
}
piidOld = pMap[i].piidDispatch;
}

if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
{
ATLTRACE(_T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
hr = E_FAIL;
break;
}
}
return hr;
}

HRESULT CComControlBase::IPersistStreamInit_Save(LPSTREAM pStm, BOOL /* fClearDirty */, ATL_PROPMAP_ENTRY* pMap)
{
_ASSERTE(pMap != NULL);
DWORD dw = _ATL_VER;
HRESULT hr = pStm->Write(&dw, sizeof(DWORD), NULL);
if (FAILED(hr))
return hr;
hr = pStm->Write(&m_sizeExtent, sizeof(m_sizeExtent), NULL);
if (FAILED(hr))
return hr;

CComPtr<IDispatch> pDispatch;
const IID* piidOld = NULL;
for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
{
if (pMap[i].szDesc == NULL)
continue;
CComVariant var;

if(pMap[i].piidDispatch != piidOld)
{
if(FAILED(ControlQueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
{
ATLTRACE(_T("Failed to get a dispatch pointer for property #%i\n"), i);
hr = E_FAIL;
break;
}
piidOld = pMap[i].piidDispatch;
}

if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
{
ATLTRACE(_T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
hr = E_FAIL;
break;
}

HRESULT hr = var.WriteToStream(pStm);
if (FAILED(hr))
break;
}
if (SUCCEEDED(hr))
m_bRequiresSave = FALSE;

return hr;
}

HRESULT CComControlBase::SendOnDataChange(DWORD advf)
{
HRESULT hRes = S_OK;
if (m_spDataAdviseHolder)
{
CComPtr<IDataObject> pdo;
if (SUCCEEDED(ControlQueryInterface(IID_IDataObject, (void**)&pdo)))
hRes = m_spDataAdviseHolder->SendOnDataChange(pdo, 0, advf);
}
return hRes;
}

HRESULT CComControlBase::IOleObject_SetClientSite(IOleClientSite *pClientSite)
{
_ASSERTE(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;
}

HRESULT CComControlBase::IOleObject_GetClientSite(IOleClientSite **ppClientSite)
{
_ASSERTE(ppClientSite);
HRESULT hRes = E_POINTER;
if (ppClientSite != NULL)
{
*ppClientSite = m_spClientSite;
m_spClientSite->AddRef();
hRes = S_OK;
}
return hRes;
}

HRESULT CComControlBase::IOleObject_Advise(IAdviseSink *pAdvSink,
DWORD *pdwConnection)
{
HRESULT hr = S_OK;
if (m_spOleAdviseHolder == NULL)
hr = CreateOleAdviseHolder(&m_spOleAdviseHolder);
if (SUCCEEDED(hr))
hr = m_spOleAdviseHolder->Advise(pAdvSink, pdwConnection);
return hr;
}

HRESULT CComControlBase::IOleObject_Close(DWORD dwSaveOption)
{
CComPtr<IOleInPlaceObject> pIPO;
ControlQueryInterface(IID_IOleInPlaceObject, (void**)&pIPO);
_ASSERTE(pIPO != NULL);
if (m_hWndCD)
{
if (m_spClientSite)
m_spClientSite->OnShowWindow(FALSE);
}

if (m_bInPlaceActive)
{
HRESULT hr = pIPO->InPlaceDeactivate();
if (FAILED(hr))
return hr;
_ASSERTE(!m_bInPlaceActive);
}
if (m_hWndCD)
{
ATLTRACE(_T("Destroying Window\n"));
if (::IsWindow(m_hWndCD))
DestroyWindow(m_hWndCD);
m_hWndCD = NULL;
}

// handle the save flag.
//
if ((dwSaveOption == OLECLOSE_SAVEIFDIRTY ||
dwSaveOption == OLECLOSE_PROMPTSAVE) && m_bRequiresSave)
{
if (m_spClientSite)
m_spClientSite->SaveObject();
SendOnSave();
}

m_spInPlaceSite.Release();
m_bNegotiatedWnd = FALSE;
m_bWndLess = FALSE;
m_bInPlaceSiteEx = FALSE;
m_spAdviseSink.Release();
return S_OK;
}

HRESULT CComControlBase::IOleInPlaceObject_InPlaceDeactivate(void)
{
CComPtr<IOleInPlaceObject> pIPO;
ControlQueryInterface(IID_IOleInPlaceObject, (void**)&pIPO);
_ASSERTE(pIPO != NULL);

if (!m_bInPlaceActive)
return S_OK;
pIPO->UIDeactivate();

m_bInPlaceActive = FALSE;

// if we have a window, tell it to go away.
//
if (m_hWndCD)
{
ATLTRACE(_T("Destroying Window\n"));
if (::IsWindow(m_hWndCD))
DestroyWindow(m_hWndCD);
m_hWndCD = NULL;
}

if (m_spInPlaceSite)
m_spInPlaceSite->OnInPlaceDeactivate();

return S_OK;
}

HRESULT CComControlBase::IOleInPlaceObject_UIDeactivate(void)
{
// if we're not UIActive, not much to do.
//
if (!m_bUIActive)
return S_OK;

m_bUIActive = FALSE;

// notify frame windows, if appropriate, that we're no longer ui-active.
//
CComPtr<IOleInPlaceFrame> spInPlaceFrame;
CComPtr<IOleInPlaceUIWindow> spInPlaceUIWindow;
OLEINPLACEFRAMEINFO frameInfo;
frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
RECT rcPos, rcClip;

HWND hwndParent;
// This call to GetWindow is a fix for Delphi
if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK)
{
m_spInPlaceSite->GetWindowContext(&spInPlaceFrame,
&spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);
if (spInPlaceUIWindow)
spInPlaceUIWindow->SetActiveObject(NULL, NULL);
if (spInPlaceFrame)
spInPlaceFrame->SetActiveObject(NULL, NULL);
}
// we don't need to explicitly release the focus here since somebody
// else grabbing the focus is what is likely to cause us to get lose it
//
m_spInPlaceSite->OnUIDeactivate(FALSE);

return S_OK;
}

HRESULT CComControlBase::IOleInPlaceObject_SetObjectRects(LPCRECT prcPos,LPCRECT prcClip)
{
if (prcPos == NULL || prcClip == NULL)
return E_POINTER;

m_rcPos = *prcPos;
if (m_hWndCD)
{
// the container wants us to clip, so figure out if we really
// need to
//
RECT rcIXect;
BOOL b = IntersectRect(&rcIXect, prcPos, prcClip);
HRGN tempRgn = NULL;
if (b && !EqualRect(&rcIXect, prcPos))
{
OffsetRect(&rcIXect, -(prcPos->left), -(prcPos->top));
tempRgn = CreateRectRgnIndirect(&rcIXect);
}

SetWindowRgn(m_hWndCD, tempRgn, TRUE);

// set our control's location, but don't change it's size at all
// [people for whom zooming is important should set that up here]
//
SIZEL size = {prcPos->right - prcPos->left, prcPos->bottom - prcPos->top};
SetWindowPos(m_hWndCD, NULL, prcPos->left,
prcPos->top, size.cx, size.cy, SWP_NOZORDER | SWP_NOACTIVATE);
}

return S_OK;
}

HRESULT CComControlBase::IOleObject_SetExtent(DWORD dwDrawAspect, SIZEL *psizel)
{
if (dwDrawAspect != DVASPECT_CONTENT)
return DV_E_DVASPECT;
if (psizel == NULL)
return E_POINTER;

BOOL bSizeMatchesNatural =
memcmp(psizel, &m_sizeNatural, sizeof(SIZE)) == 0;

if (m_bAutoSize) //object can't do any other size
return (bSizeMatchesNatural) ? S_OK : E_FAIL;

BOOL bResized = FALSE;
if (memcmp(psizel, &m_sizeExtent, sizeof(SIZE)) != 0)
{
m_sizeExtent = *psizel;
bResized = TRUE;
}
if (m_bResizeNatural && !bSizeMatchesNatural)
{
m_sizeNatural = *psizel;
bResized = TRUE;
}

if (m_bRecomposeOnResize && bResized)
{
SendOnDataChange();
FireViewChange();
}
return S_OK;
}

HRESULT CComControlBase::IViewObject_Draw(DWORD dwDrawAspect, LONG lindex,
void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDev, HDC hdcDraw,
LPCRECTL prcBounds, LPCRECTL prcWBounds)
{
ATLTRACE(_T("Draw dwDrawAspect=%x lindex=%d ptd=%x hic=%x hdc=%x\n"),
dwDrawAspect, lindex, ptd, hicTargetDev, hdcDraw);
#ifdef _DEBUG
if (prcBounds == NULL)
ATLTRACE(_T("\tprcBounds=NULL\n"));
else
ATLTRACE(_T("\tprcBounds=%d,%d,%d,%d\n"), prcBounds->left,
prcBounds->top, prcBounds->right, prcBounds->bottom);
if (prcWBounds == NULL)
ATLTRACE(_T("\tprcWBounds=NULL\n"));
else
ATLTRACE(_T("\tprcWBounds=%d,%d,%d,%d\n"), prcWBounds->left,
prcWBounds->top, prcWBounds->right, prcWBounds->bottom);
#endif
_ASSERTE(prcBounds != NULL | m_bWndLess);

if (prcBounds == NULL)
{
if (!m_bWndLess)
return E_INVALIDARG;
prcBounds = (RECTL*)&m_rcPos;
}

// support the aspects required for multi-pass drawing
switch (dwDrawAspect)
{
case DVASPECT_CONTENT:
case DVASPECT_OPAQUE:
case DVASPECT_TRANSPARENT:
break;
default:
_ASSERTE(FALSE);
return DV_E_DVASPECT;
break;
}

// make sure nobody forgets to do this
if (ptd == NULL)
hicTargetDev = NULL;

BOOL bOptimize = FALSE;
if (pvAspect && ((DVASPECTINFO *)pvAspect)->cb >= sizeof(DVASPECTINFO))
bOptimize = (((DVASPECTINFO *)pvAspect)->dwFlags & DVASPECTINFOFLAG_CANOPTIMIZE);

ATL_DRAWINFO di;
memset(&di, 0, sizeof(di));
di.cbSize = sizeof(di);
di.dwDrawAspect = dwDrawAspect;
di.lindex = lindex;
di.ptd = ptd;
di.hicTargetDev = hicTargetDev;
di.hdcDraw = hdcDraw;
di.prcBounds = prcBounds;
di.prcWBounds = prcWBounds;
di.bOptimize = bOptimize;
return OnDrawAdvanced(di);
}

HRESULT CComControlBase::IDataObject_GetData(FORMATETC *pformatetcIn,
STGMEDIUM *pmedium)
{
if (pmedium == NULL)
return E_POINTER;
memset(pmedium, 0, sizeof(STGMEDIUM));
ATLTRACE(_T("Format = %x\n"), pformatetcIn->cfFormat);
ATLTRACE(_T("TYMED = %x\n"), pformatetcIn->tymed);

if ((pformatetcIn->tymed & TYMED_MFPICT) == 0)
return DATA_E_FORMATETC;

SIZEL sizeMetric, size;
if (m_bDrawFromNatural)
sizeMetric = m_sizeNatural;
else
sizeMetric = m_sizeExtent;
if (!m_bDrawGetDataInHimetric)
AtlHiMetricToPixel(&sizeMetric, &size);
else
size = sizeMetric;
RECTL rectl = {0 ,0, size.cx, size.cy};

ATL_DRAWINFO di;
memset(&di, 0, sizeof(di));
di.cbSize = sizeof(di);
di.dwDrawAspect = DVASPECT_CONTENT;
di.lindex = -1;
di.ptd = NULL;
di.hicTargetDev = NULL;
di.prcBounds = &rectl;
di.prcWBounds = &rectl;
di.bOptimize = TRUE; //we do a SaveDC/RestoreDC
di.bRectInHimetric = m_bDrawGetDataInHimetric;
// create appropriate memory metafile DC
di.hdcDraw = CreateMetaFile(NULL);

// create attribute DC according to pformatetcIn->ptd

SaveDC(di.hdcDraw);
SetWindowOrgEx(di.hdcDraw, 0, 0, NULL);
SetWindowExtEx(di.hdcDraw, rectl.right, rectl.bottom, NULL);
OnDrawAdvanced(di);
RestoreDC(di.hdcDraw, -1);

HMETAFILE hMF = CloseMetaFile(di.hdcDraw);
if (hMF == NULL)
return E_UNEXPECTED;

HGLOBAL hMem=GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));

if (NULL==hMem)
{
DeleteMetaFile(hMF);
return ResultFromScode(STG_E_MEDIUMFULL);
}

LPMETAFILEPICT pMF=(LPMETAFILEPICT)GlobalLock(hMem);
pMF->hMF=hMF;
pMF->mm=MM_ANISOTROPIC;
pMF->xExt=sizeMetric.cx;
pMF->yExt=sizeMetric.cy;
GlobalUnlock(hMem);

pmedium->tymed = TYMED_MFPICT;
pmedium->hGlobal = hMem;
pmedium->pUnkForRelease = NULL;

return S_OK;

}

HRESULT CComControlBase::FireViewChange()
{
if (m_bInPlaceActive)
{
// Active
if (m_hWndCD != NULL)
return ::InvalidateRect(m_hWndCD, NULL, TRUE); // Window based
if (m_spInPlaceSite != NULL)
return m_spInPlaceSite->InvalidateRect(NULL, TRUE); // Windowless
}
// Inactive
SendOnViewChange(DVASPECT_CONTENT);
return S_OK;
}

void CComControlBase::GetZoomInfo(ATL_DRAWINFO& di)
{
const RECTL& rcPos = *di.prcBounds;
SIZEL sizeDen;
if (m_bDrawFromNatural)
sizeDen = m_sizeNatural;
else
sizeDen = m_sizeExtent;
if (!di.bRectInHimetric)
AtlHiMetricToPixel(&sizeDen, &sizeDen);
SIZEL sizeNum = {rcPos.right-rcPos.left, rcPos.bottom-rcPos.top};
di.ZoomNum.cx = sizeNum.cx;
di.ZoomNum.cy = sizeNum.cy;
di.ZoomDen.cx = sizeDen.cx;
di.ZoomDen.cy = sizeDen.cy;
if (sizeDen.cx == 0 || sizeDen.cy == 0 ||
sizeNum.cx == 0 || sizeNum.cy == 0)
{
di.ZoomNum.cx = di.ZoomNum.cy = di.ZoomDen.cx = di.ZoomDen.cy = 1;
di.bZoomed = FALSE;
}
else if (sizeNum.cx != sizeDen.cx || sizeNum.cy != sizeDen.cy)
di.bZoomed = TRUE;
else
di.bZoomed = FALSE;
}

HRESULT CComControlBase::OnDrawAdvanced(ATL_DRAWINFO& di)
{
BOOL bDeleteDC = FALSE;
if (di.hicTargetDev == NULL)
{
di.hicTargetDev = AtlCreateTargetDC(di.hdcDraw, di.ptd);
bDeleteDC = (di.hicTargetDev != di.hdcDraw);
}
RECTL rectBoundsDP = *di.prcBounds;
BOOL bMetafile = GetDeviceCaps(di.hdcDraw, TECHNOLOGY) == DT_METAFILE;
if (!bMetafile)
{
::LPtoDP(di.hicTargetDev, (LPPOINT)&rectBoundsDP, 2);
SaveDC(di.hdcDraw);
SetMapMode(di.hdcDraw, MM_TEXT);
SetWindowOrgEx(di.hdcDraw, 0, 0, NULL);
SetViewportOrgEx(di.hdcDraw, 0, 0, NULL);
di.bOptimize = TRUE; //since we save the DC we can do this
}
di.prcBounds = &rectBoundsDP;
GetZoomInfo(di);

HRESULT hRes = OnDraw(di);
if (bDeleteDC)
::DeleteDC(di.hicTargetDev);
if (!bMetafile)
RestoreDC(di.hdcDraw, -1);
return hRes;
}

LRESULT CComControlBase::OnPaint(UINT /* nMsg */, WPARAM /* wParam */,
LPARAM /* lParam */, BOOL& /* lResult */)
{
RECT rc;
PAINTSTRUCT ps;

HDC hdc = ::BeginPaint(m_hWndCD, &ps);
if (hdc == NULL)
return 0;
::GetClientRect(m_hWndCD, &rc);

ATL_DRAWINFO di;
memset(&di, 0, sizeof(di));
di.cbSize = sizeof(di);
di.dwDrawAspect = DVASPECT_CONTENT;
di.lindex = -1;
di.hdcDraw = hdc;
di.prcBounds = (LPCRECTL)&rc;

OnDrawAdvanced(di);
::EndPaint(m_hWndCD, &ps);
return 0;
}

#ifndef ATL_NO_NAMESPACE
}; //namespace ATL
#endif

///////////////////////////////////////////////////////////////////////////////
//All Global stuff goes below this line
///////////////////////////////////////////////////////////////////////////////

#ifndef _ATL_DLL
ATLAPI_(HDC) AtlCreateTargetDC(HDC hdc, DVTARGETDEVICE* ptd)
{
USES_CONVERSION;

// cases hdc, ptd, hdc is metafile, hic
// NULL, NULL, n/a, Display
// NULL, !NULL, n/a, ptd
// !NULL, NULL, FALSE, hdc
// !NULL, NULL, TRUE, display
// !NULL, !NULL, FALSE, ptd
// !NULL, !NULL, TRUE, ptd

if (ptd != NULL)
{
LPDEVMODEOLE lpDevMode;
LPOLESTR lpszDriverName;
LPOLESTR lpszDeviceName;
LPOLESTR lpszPortName;


if (ptd->tdExtDevmodeOffset == 0)
lpDevMode = NULL;
else
lpDevMode = (LPDEVMODEOLE) ((LPSTR)ptd + ptd->tdExtDevmodeOffset);

lpszDriverName = (LPOLESTR)((BYTE*)ptd + ptd->tdDriverNameOffset);
lpszDeviceName = (LPOLESTR)((BYTE*)ptd + ptd->tdDeviceNameOffset);
lpszPortName = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset);

return ::CreateDC(OLE2CT(lpszDriverName), OLE2CT(lpszDeviceName),
OLE2CT(lpszPortName), DEVMODEOLE2T(lpDevMode));
}
else if (hdc == NULL || GetDeviceCaps(hdc, TECHNOLOGY) == DT_METAFILE)
return ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
else
return hdc;
}

#define HIMETRIC_PER_INCH 2540
#define MAP_PIX_TO_LOGHIM(x,ppli) ( (HIMETRIC_PER_INCH*(x) + ((ppli)>>1)) / (ppli) )
#define MAP_LOGHIM_TO_PIX(x,ppli) ( ((ppli)*(x) + HIMETRIC_PER_INCH/2) / HIMETRIC_PER_INCH )

ATLAPI_(void) AtlHiMetricToPixel(const SIZEL * lpSizeInHiMetric, LPSIZEL lpSizeInPix)
{
int nPixelsPerInchX; // Pixels per logical inch along width
int nPixelsPerInchY; // Pixels per logical inch along height

HDC hDCScreen = GetDC(NULL);
_ASSERTE(hDCScreen != NULL);
nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX);
nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY);
ReleaseDC(NULL, hDCScreen);

lpSizeInPix->cx = MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cx, nPixelsPerInchX);
lpSizeInPix->cy = MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cy, nPixelsPerInchY);
}

ATLAPI_(void) AtlPixelToHiMetric(const SIZEL * lpSizeInPix, LPSIZEL lpSizeInHiMetric)
{
int nPixelsPerInchX; // Pixels per logical inch along width
int nPixelsPerInchY; // Pixels per logical inch along height

HDC hDCScreen = GetDC(NULL);
_ASSERTE(hDCScreen != NULL);
nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX);
nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY);
ReleaseDC(NULL, hDCScreen);

lpSizeInHiMetric->cx = MAP_PIX_TO_LOGHIM(lpSizeInPix->cx, nPixelsPerInchX);
lpSizeInHiMetric->cy = MAP_PIX_TO_LOGHIM(lpSizeInPix->cy, nPixelsPerInchY);
}
#endif