home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
occsite.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
90KB
|
3,525 lines
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "occimpl.h"
#include "msdadc.h"
#ifdef AFX_OCC_SEG
#pragma code_seg(AFX_OCC_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
#define S_QUICKACTIVATED S_FALSE
#include "initguid.h"
#define DBINITCONSTANTS
#define INITGUID
DEFINE_GUID(IID_IDataSourceListener,0x7C0FFAB2L,0xCD84,0x11D0,0x94,0x9A,0x00,0xA0,0xC9,0x11,0x10,0xED);
DEFINE_GUID(IID_IDataSource,0x7c0ffab3L, 0xcd84, 0x11d0, 0x94, 0x9a, 0x00, 0xa0, 0xc9, 0x11, 0x10, 0xed);
/////////////////////////////////////////////////////////////////////////////
// COleControlSite
BEGIN_INTERFACE_MAP(COleControlSite, CCmdTarget)
INTERFACE_PART(COleControlSite, IID_IOleClientSite, OleClientSite)
INTERFACE_PART(COleControlSite, IID_IOleInPlaceSite, OleIPSite)
INTERFACE_PART(COleControlSite, IID_IOleControlSite, OleControlSite)
INTERFACE_PART(COleControlSite, IID_IDispatch, AmbientProps)
INTERFACE_PART(COleControlSite, IID_IBoundObjectSite, BoundObjectSite)
INTERFACE_PART(COleControlSite, IID_INotifyDBEvents, NotifyDBEvents)
INTERFACE_PART(COleControlSite, IID_IRowsetNotify, RowsetNotify)
END_INTERFACE_MAP()
COleControlSite::COleControlSite(COleControlContainer* pCtrlCont) :
m_pCtrlCont(pCtrlCont),
m_pWndCtrl(NULL),
m_nID((UINT)-1),
m_pObject(NULL),
m_pInPlaceObject(NULL),
m_pActiveObject(NULL),
m_dwEventSink(0),
m_dwPropNotifySink(0),
m_dwMiscStatus(0),
m_dwNotifyDBEvents(0),
m_pDataSourceControl(NULL),
m_pDSCSite(NULL),
m_defdispid(0),
m_dwType(0),
m_pBindings(NULL),
m_bIgnoreNotify(FALSE),
m_bIsDirty(FALSE)
{
memset(&m_varResult, 0, sizeof(VARIANT));
m_varResult.vt = VT_EMPTY;
}
COleControlSite::~COleControlSite()
{
delete m_pDataSourceControl;
DetachWindow();
DisconnectSink(m_iidEvents, m_dwEventSink);
DisconnectSink(IID_IPropertyNotifySink, m_dwPropNotifySink);
DisconnectSink(IID_INotifyDBEvents, m_dwNotifyDBEvents);
if (m_pInPlaceObject != NULL)
{
m_pInPlaceObject->InPlaceDeactivate();
m_pInPlaceObject->Release();
m_pInPlaceObject = NULL;
}
if (m_pActiveObject != NULL)
{
m_pActiveObject->Release();
m_pActiveObject = NULL;
}
if (m_pObject != NULL)
{
m_pObject->SetClientSite(NULL);
m_pObject->Close(OLECLOSE_NOSAVE);
m_pObject->Release();
m_pObject = NULL;
}
::VariantClear(&m_varResult);
BindProperty(DISPID_UNKNOWN, NULL); // gets rid of complex bindings
if (m_defdispid != 0 && m_pDSCSite != NULL &&
m_pDSCSite->m_pDataSourceControl != NULL)
{
// get rid of simple bindings
m_pDSCSite->m_pDataSourceControl->BindProp(this, FALSE);
}
}
BOOL COleControlSite::SetExtent()
{
CSize size(m_rect.Size());
CClientDC dc(NULL);
dc.DPtoHIMETRIC(&size);
HRESULT hr;
if (SUCCEEDED(hr = m_pObject->SetExtent(DVASPECT_CONTENT, (SIZEL*)&size)))
{
if (SUCCEEDED(m_pObject->GetExtent(DVASPECT_CONTENT, (SIZEL*)&size)))
{
dc.HIMETRICtoDP(&size);
m_rect.right = m_rect.left + size.cx;
m_rect.bottom = m_rect.top + size.cy;
}
}
return SUCCEEDED(hr);
}
HRESULT COleControlSite::CreateControl(CWnd* pWndCtrl, REFCLSID clsid,
LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, UINT nID,
CFile* pPersist, BOOL bStorage, BSTR bstrLicKey)
{
CRect rect2( rect );
CPoint pt;
CSize size;
pt = rect2.TopLeft();
size = rect2.Size();
return( CreateControl( pWndCtrl, clsid, lpszWindowName, dwStyle, &pt, &size,
nID, pPersist, bStorage, bstrLicKey ) );
}
HRESULT COleControlSite::CreateControl(CWnd* pWndCtrl, REFCLSID clsid,
LPCTSTR lpszWindowName, DWORD dwStyle, const POINT* ppt, const SIZE* psize,
UINT nID, CFile* pPersist, BOOL bStorage, BSTR bstrLicKey)
{
HRESULT hr = E_FAIL;
m_hWnd = NULL;
CSize size;
// Connect the OLE Control with its proxy CWnd object
if (pWndCtrl != NULL)
{
ASSERT(pWndCtrl->m_pCtrlSite == NULL);
m_pWndCtrl = pWndCtrl;
pWndCtrl->m_pCtrlSite = this;
}
// Initialize OLE, if necessary
_AFX_THREAD_STATE* pState = AfxGetThreadState();
if (!pState->m_bNeedTerm && !AfxOleInit())
return hr;
if (SUCCEEDED(hr = CreateOrLoad(clsid, pPersist, bStorage, bstrLicKey)))
{
ASSERT(m_pObject != NULL);
m_nID = nID;
if (psize == NULL)
{
// If psize is NULL, ask the object how big it wants to be.
CClientDC dc(NULL);
m_pObject->GetExtent(DVASPECT_CONTENT, &size);
dc.HIMETRICtoDP(&size);
m_rect = CRect(*ppt, size);
}
else
{
m_rect = CRect(*ppt, *psize);
}
m_dwStyleMask = WS_GROUP | WS_TABSTOP;
if (m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON)
m_dwStyleMask |= BS_DEFPUSHBUTTON;
if (m_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME)
dwStyle &= ~WS_VISIBLE;
m_dwStyle = dwStyle & m_dwStyleMask;
// If control wasn't quick-activated, then connect sinks now.
if (hr != S_QUICKACTIVATED)
{
m_dwEventSink = ConnectSink(m_iidEvents, &m_xEventSink);
m_dwPropNotifySink = ConnectSink(IID_IPropertyNotifySink,
&m_xPropertyNotifySink);
}
m_dwNotifyDBEvents = ConnectSink(IID_INotifyDBEvents, &m_xNotifyDBEvents);
// Now that the object has been created, attempt to
// in-place activate it.
SetExtent();
if (SUCCEEDED(hr = m_pObject->QueryInterface(IID_IOleInPlaceObject,
(LPVOID*)&m_pInPlaceObject)))
{
if (dwStyle & WS_VISIBLE)
{
// control is visible: just activate it
hr = DoVerb(OLEIVERB_INPLACEACTIVATE);
}
else
{
// control is not visible: activate off-screen, hide, then move
m_rect.OffsetRect(-32000, -32000);
if (SUCCEEDED(hr = DoVerb(OLEIVERB_INPLACEACTIVATE)) &&
SUCCEEDED(hr = DoVerb(OLEIVERB_HIDE)))
{
m_rect.OffsetRect(32000, 32000);
hr = m_pInPlaceObject->SetObjectRects(m_rect, m_rect);
}
}
}
else
{
TRACE1("IOleInPlaceObject not supported on OLE control (dialog ID %d).\n", nID);
TRACE1(">>> Result code: 0x%08lx\n", hr);
}
if (SUCCEEDED(hr))
GetControlInfo();
// if QueryInterface or activation failed, cleanup everything
if (FAILED(hr))
{
if (m_pInPlaceObject != NULL)
{
m_pInPlaceObject->Release();
m_pInPlaceObject = NULL;
}
DisconnectSink(m_iidEvents, m_dwEventSink);
DisconnectSink(IID_IPropertyNotifySink, m_dwPropNotifySink);
DisconnectSink(IID_INotifyDBEvents, m_dwNotifyDBEvents);
m_dwEventSink = 0;
m_dwPropNotifySink = 0;
m_dwNotifyDBEvents = 0;
m_pObject->Release();
m_pObject = NULL;
}
}
if (SUCCEEDED(hr))
{
AttachWindow();
ASSERT(m_hWnd != NULL);
// Initialize the control's Caption or Text property, if any
if (lpszWindowName != NULL)
SetWindowText(lpszWindowName);
// Initialize styles
ModifyStyle(0, m_dwStyle | (dwStyle & (WS_DISABLED|WS_BORDER)), 0);
}
return hr;
}
BOOL COleControlSite::DestroyControl()
{
ASSERT(m_hWnd != NULL); // was control ever successfully created?
m_pCtrlCont->m_siteMap.RemoveKey(m_hWnd);
//VBBUG: VB controls will crash if IOleObject::Close is called on them
// when they have focus (and unfortunately, deactivating them does not
// always move the focus). To work around this problem, we always hide
// the control before closing it.
ShowWindow(SW_HIDE);
// Now it is safe to close the control.
delete this;
return TRUE;
}
AFX_STATIC HRESULT AFXAPI _AfxCoCreateInstanceLic(REFCLSID clsid, LPUNKNOWN pUnkOuter,
DWORD dwClsCtx, REFIID iid, LPVOID* ppv, BSTR bstrLicKey)
{
HRESULT hr;
if (bstrLicKey == NULL)
{
LPCLASSFACTORY pClassFactory = NULL;
if (SUCCEEDED(hr = CoGetClassObject(clsid, dwClsCtx, NULL,
IID_IClassFactory, (void**)&pClassFactory)))
{
ASSERT(pClassFactory != NULL);
hr = pClassFactory->CreateInstance(pUnkOuter, iid, ppv);
pClassFactory->Release();
}
}
else
{
LPCLASSFACTORY2 pClassFactory = NULL;
if (SUCCEEDED(hr = CoGetClassObject(clsid, dwClsCtx, NULL,
IID_IClassFactory2, (void**)&pClassFactory)))
{
ASSERT(pClassFactory != NULL);
hr = pClassFactory->CreateInstanceLic(pUnkOuter, NULL, iid,
bstrLicKey, ppv);
pClassFactory->Release();
}
}
return hr;
}
AFX_STATIC_DATA const struct { DISPID dwDispID; DWORD dwFlag; } _afxAmbients[] =
{
{ DISPID_AMBIENT_USERMODE, QACONTAINER_USERMODE },
{ DISPID_AMBIENT_UIDEAD, QACONTAINER_UIDEAD },
{ DISPID_AMBIENT_SHOWGRABHANDLES, QACONTAINER_SHOWGRABHANDLES },
{ DISPID_AMBIENT_SHOWHATCHING, QACONTAINER_SHOWHATCHING },
{ DISPID_AMBIENT_DISPLAYASDEFAULT, QACONTAINER_DISPLAYASDEFAULT },
{ DISPID_AMBIENT_AUTOCLIP, QACONTAINER_AUTOCLIP },
{ DISPID_AMBIENT_MESSAGEREFLECT, QACONTAINER_MESSAGEREFLECT },
{ DISPID_AMBIENT_SUPPORTSMNEMONICS, QACONTAINER_SUPPORTSMNEMONICS },
};
BOOL COleControlSite::QuickActivate()
{
BOOL bQuickActivated = FALSE;
IQuickActivate* pQuick = NULL;
if (SUCCEEDED(m_pObject->QueryInterface(IID_IQuickActivate,
reinterpret_cast<void**>(&pQuick))))
{
ASSERT(pQuick != NULL);
// Initialize QACONTAINER structure.
QACONTAINER qaContainer;
qaContainer.cbSize = sizeof(QACONTAINER);
qaContainer.pClientSite = &m_xOleClientSite;
qaContainer.pAdviseSink = NULL;
qaContainer.pPropertyNotifySink = &m_xPropertyNotifySink;
qaContainer.pUnkEventSink = &m_xEventSink;
qaContainer.pUndoMgr = NULL;
qaContainer.hpal = NULL;
qaContainer.pBindHost = NULL;
// Fill ambient property values in QACONTAINER.
COleVariant var;
CWnd* pWndContain = m_pCtrlCont->m_pWnd;
qaContainer.dwAmbientFlags = 0;
for (int i = 0; i < _countof(_afxAmbients); i++)
{
pWndContain->OnAmbientProperty(this, _afxAmbients[i].dwDispID, &var);
if (V_BOOL(&var))
qaContainer.dwAmbientFlags |= _afxAmbients[i].dwFlag;
}
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_FORECOLOR, &var);
qaContainer.colorFore = V_I4(&var);
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_BACKCOLOR, &var);
qaContainer.colorBack = V_I4(&var);
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_APPEARANCE, &var);
qaContainer.dwAppearance = V_I2(&var);
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_LOCALEID, &var);
qaContainer.lcid = V_I4(&var);
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_FONT, &var);
if (FAILED(V_DISPATCH(&var)->QueryInterface(IID_IFont,
reinterpret_cast<void**>(&qaContainer.pFont))))
{
qaContainer.pFont = NULL;
}
// Initialize QACONTROL structure.
QACONTROL qaControl;
qaControl.cbSize = sizeof(QACONTROL);
// Do the quick activation.
if (SUCCEEDED(pQuick->QuickActivate(&qaContainer, &qaControl)))
{
// Extract return values from QACONTROL structure.
m_dwMiscStatus = qaControl.dwMiscStatus;
m_dwEventSink = qaControl.dwEventCookie;
m_dwPropNotifySink = qaControl.dwPropNotifyCookie;
bQuickActivated = TRUE;
}
pQuick->Release();
if (qaContainer.pFont != NULL)
qaContainer.pFont->Release();
}
return bQuickActivated;
}
HRESULT COleControlSite::CreateOrLoad(REFCLSID clsid, CFile* pFile,
BOOL bStorage, BSTR bstrLicKey)
{
ASSERT(m_pObject == NULL);
#ifdef _DEBUG
OLECHAR wszClsid[40];
StringFromGUID2(clsid, wszClsid, 40);
#endif //_DEBUG
HRESULT hr;
if (FAILED(hr = _AfxCoCreateInstanceLic(clsid, NULL,
CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IOleObject,
(void**)&m_pObject, bstrLicKey)))
{
TRACE1("CoCreateInstance of OLE control %ls failed.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
TRACE0(">>> Is the control is properly registered?\n");
return hr;
}
LPPERSISTSTREAMINIT pPersStm = NULL;
LPPERSISTSTORAGE pPersStg = NULL;
LPPERSISTMEMORY pPersMem = NULL;
GetEventIID(&m_iidEvents);
// Try to quick-activate first
BOOL bQuickActivated = QuickActivate();
if (!bQuickActivated)
{
m_pObject->GetMiscStatus(DVASPECT_CONTENT, &m_dwMiscStatus);
// set client site first, if appropriate
if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
{
if (FAILED(hr = m_pObject->SetClientSite(&m_xOleClientSite)))
{
TRACE1("SetClientSite on OLE control %ls failed.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
goto CreateOrLoadFailed;
}
}
}
ASSERT(!bStorage || pFile != NULL);
// initialize via IPersistMemory (direct buffering)
if (pFile != NULL && !bStorage &&
SUCCEEDED(m_pObject->QueryInterface(IID_IPersistMemory, (void**)&pPersMem)) &&
pFile->GetBufferPtr(CFile::bufferCheck) != 0)
{
ASSERT(pPersMem != NULL);
// file supports direct buffering, get its buffer pointer and size
LPVOID pvBuffer = NULL;
LPVOID pvEnd;
ULONG cbBuffer = pFile->GetBufferPtr(
CFile::bufferRead, (UINT)-1, &pvBuffer, &pvEnd);
ASSERT(((LPBYTE)pvEnd - (LPBYTE)pvBuffer) == (int)cbBuffer);
// and then load it directly
hr = pPersMem->Load(pvBuffer, cbBuffer);
pPersMem->Release();
pPersMem = NULL;
if (FAILED(hr))
goto CreateOrLoadFailed;
}
// initialize via IPersistStreamInit
else if (!bStorage && SUCCEEDED(m_pObject->QueryInterface(
IID_IPersistStreamInit, (void**)&pPersStm)))
{
ASSERT(pPersStm != NULL);
if (pFile == NULL)
{
// just call InitNew
hr = pPersStm->InitNew();
}
else
{
// open an IStream on the data and pass it to Load
CArchive ar(pFile, CArchive::load);
CArchiveStream stm(&ar);
hr = pPersStm->Load(&stm);
}
pPersStm->Release();
if (FAILED(hr))
{
TRACE1("InitNew or Load on OLE control %ls failed.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
goto CreateOrLoadFailed;
}
}
// initialize via IPersistStorage
else if (SUCCEEDED(m_pObject->QueryInterface(
IID_IPersistStorage, (void**)&pPersStg)))
{
ASSERT(pPersStg != NULL);
if (pFile == NULL)
{
// create a scratch IStorage and pass it to InitNew
LPLOCKBYTES pLockBytes = NULL;
if (SUCCEEDED(hr = CreateILockBytesOnHGlobal(NULL, TRUE,
&pLockBytes)))
{
ASSERT(pLockBytes != NULL);
LPSTORAGE pStorage = NULL;
if (SUCCEEDED(hr = StgCreateDocfileOnILockBytes(pLockBytes,
STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0,
&pStorage)))
{
ASSERT(pStorage != NULL);
hr = pPersStg->InitNew(pStorage);
pStorage->Release();
}
pLockBytes->Release();
}
}
else if (bStorage)
{
// copy data to an HGLOBAL, so we can build an IStorage on it
UINT cb = pFile->GetLength();
HGLOBAL hGlobal;
BYTE* pbData;
if (((hGlobal = GlobalAlloc(GMEM_FIXED, cb)) != NULL) &&
((pbData = (BYTE*)GlobalLock(hGlobal)) != NULL))
{
pFile->Read(pbData, cb);
GlobalUnlock(hGlobal);
}
else
{
hr = E_OUTOFMEMORY;
hGlobal = NULL;
}
// open an IStorage on the data and pass it to Load
LPLOCKBYTES pLockBytes = NULL;
if ((hGlobal != NULL) &&
SUCCEEDED(hr = CreateILockBytesOnHGlobal(hGlobal, TRUE,
&pLockBytes)))
{
ASSERT(pLockBytes != NULL);
LPSTORAGE pStorage = NULL;
if (SUCCEEDED(hr = StgOpenStorageOnILockBytes(pLockBytes, NULL,
STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &pStorage)))
{
ASSERT(pStorage != NULL);
hr = pPersStg->Load(pStorage);
pStorage->Release();
}
pLockBytes->Release();
}
}
else
{
hr = E_UNEXPECTED;
}
pPersStg->Release();
if (FAILED(hr))
{
TRACE1("InitNew or Load on OLE control %ls failed.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
goto CreateOrLoadFailed;
}
}
else
{
TRACE1("Persistence not supported on OLE control %ls.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
goto CreateOrLoadFailed;
}
if (!bQuickActivated)
{
// set client site last, if appropriate
if (!(m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
{
if (FAILED(hr = m_pObject->SetClientSite(&m_xOleClientSite)))
{
TRACE1("SetClientSite on OLE control %ls failed.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
goto CreateOrLoadFailed;
}
}
}
CreateOrLoadFailed:
if (FAILED(hr) && (m_pObject != NULL))
{
m_pObject->Close(OLECLOSE_NOSAVE);
m_pObject->Release();
m_pObject = NULL;
}
if (pPersMem != NULL)
pPersMem->Release();
if (bQuickActivated && SUCCEEDED(hr))
hr = S_QUICKACTIVATED;
return hr;
}
UINT COleControlSite::GetID()
{
return m_nID;
}
HRESULT COleControlSite::DoVerb(LONG nVerb, LPMSG lpMsg)
{
return m_pObject->DoVerb(nVerb, lpMsg, &m_xOleClientSite, 0,
m_pCtrlCont->m_pWnd->m_hWnd, m_rect);
}
BOOL COleControlSite::IsDefaultButton()
{
return ((m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON) &&
(m_dwStyle & BS_DEFPUSHBUTTON));
}
DWORD COleControlSite::GetDefBtnCode()
{
if (m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON)
return (m_dwStyle & BS_DEFPUSHBUTTON) ?
DLGC_DEFPUSHBUTTON :
DLGC_UNDEFPUSHBUTTON;
else
return 0;
}
void COleControlSite::SetDefaultButton(BOOL bDefault)
{
if (!(m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON))
return;
if (((m_dwStyle & BS_DEFPUSHBUTTON) != 0) == bDefault)
return;
m_dwStyle ^= BS_DEFPUSHBUTTON;
// Notify control that its "defaultness" has changed.
LPOLECONTROL pOleCtl = NULL;
if (SUCCEEDED(m_pObject->QueryInterface(IID_IOleControl,
(LPVOID*)&pOleCtl)))
{
ASSERT(pOleCtl != NULL);
pOleCtl->OnAmbientPropertyChange(DISPID_AMBIENT_DISPLAYASDEFAULT);
pOleCtl->Release();
}
}
DWORD COleControlSite::ConnectSink(REFIID iid, LPUNKNOWN punkSink)
{
ASSERT(m_pObject != NULL);
LPCONNECTIONPOINTCONTAINER pConnPtCont;
if ((m_pObject != NULL) &&
SUCCEEDED(m_pObject->QueryInterface(IID_IConnectionPointContainer,
(LPVOID*)&pConnPtCont)))
{
ASSERT(pConnPtCont != NULL);
LPCONNECTIONPOINT pConnPt = NULL;
DWORD dwCookie = 0;
if (SUCCEEDED(pConnPtCont->FindConnectionPoint(iid, &pConnPt)))
{
ASSERT(pConnPt != NULL);
pConnPt->Advise(punkSink, &dwCookie);
pConnPt->Release();
}
pConnPtCont->Release();
return dwCookie;
}
return 0;
}
void COleControlSite::DisconnectSink(REFIID iid, DWORD dwCookie)
{
if (dwCookie == 0 || m_pObject == NULL)
return;
LPCONNECTIONPOINTCONTAINER pConnPtCont;
if (SUCCEEDED(m_pObject->QueryInterface(IID_IConnectionPointContainer,
(LPVOID*)&pConnPtCont)))
{
ASSERT(pConnPtCont != NULL);
LPCONNECTIONPOINT pConnPt = NULL;
if (SUCCEEDED(pConnPtCont->FindConnectionPoint(iid, &pConnPt)))
{
ASSERT(pConnPt != NULL);
pConnPt->Unadvise(dwCookie);
pConnPt->Release();
}
pConnPtCont->Release();
}
}
#define IMPLTYPE_MASK \
(IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE | IMPLTYPEFLAG_FRESTRICTED)
#define IMPLTYPE_DEFAULTSOURCE \
(IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE)
BOOL COleControlSite::GetEventIID(IID* piid)
{
*piid = GUID_NULL;
ASSERT(m_pObject != NULL);
// Use IProvideClassInfo2, if control supports it.
LPPROVIDECLASSINFO2 pPCI2 = NULL;
if (SUCCEEDED(m_pObject->QueryInterface(IID_IProvideClassInfo2,
(LPVOID*)&pPCI2)))
{
ASSERT(pPCI2 != NULL);
if (SUCCEEDED(pPCI2->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID, piid)))
ASSERT(!IsEqualIID(*piid, GUID_NULL));
else
ASSERT(IsEqualIID(*piid, GUID_NULL));
pPCI2->Release();
}
// Fall back on IProvideClassInfo, if IProvideClassInfo2 not supported.
LPPROVIDECLASSINFO pPCI = NULL;
if (IsEqualIID(*piid, GUID_NULL) &&
SUCCEEDED(m_pObject->QueryInterface(IID_IProvideClassInfo,
(LPVOID*)&pPCI)))
{
ASSERT(pPCI != NULL);
LPTYPEINFO pClassInfo = NULL;
if (SUCCEEDED(pPCI->GetClassInfo(&pClassInfo)))
{
ASSERT(pClassInfo != NULL);
LPTYPEATTR pClassAttr;
if (SUCCEEDED(pClassInfo->GetTypeAttr(&pClassAttr)))
{
ASSERT(pClassAttr != NULL);
ASSERT(pClassAttr->typekind == TKIND_COCLASS);
// Search for typeinfo of the default events interface.
int nFlags;
HREFTYPE hRefType;
for (unsigned int i = 0; i < pClassAttr->cImplTypes; i++)
{
if (SUCCEEDED(pClassInfo->GetImplTypeFlags(i, &nFlags)) &&
((nFlags & IMPLTYPE_MASK) == IMPLTYPE_DEFAULTSOURCE))
{
// Found it. Now look at its attributes to get IID.
LPTYPEINFO pEventInfo = NULL;
if (SUCCEEDED(pClassInfo->GetRefTypeOfImplType(i,
&hRefType)) &&
SUCCEEDED(pClassInfo->GetRefTypeInfo(hRefType,
&pEventInfo)))
{
ASSERT(pEventInfo != NULL);
LPTYPEATTR pEventAttr;
if (SUCCEEDED(pEventInfo->GetTypeAttr(&pEventAttr)))
{
ASSERT(pEventAttr != NULL);
*piid = pEventAttr->guid;
pEventInfo->ReleaseTypeAttr(pEventAttr);
}
pEventInfo->Release();
}
break;
}
}
pClassInfo->ReleaseTypeAttr(pClassAttr);
}
pClassInfo->Release();
}
pPCI->Release();
}
return (!IsEqualIID(*piid, GUID_NULL));
}
void COleControlSite::GetControlInfo()
{
memset(&m_ctlInfo, 0, sizeof(CONTROLINFO));
m_ctlInfo.cb = sizeof(CONTROLINFO);
LPOLECONTROL pOleCtl = NULL;
if (SUCCEEDED(m_pObject->QueryInterface(IID_IOleControl,
(LPVOID*)&pOleCtl)))
{
ASSERT(pOleCtl != NULL);
pOleCtl->GetControlInfo(&m_ctlInfo);
pOleCtl->Release();
}
}
BOOL COleControlSite::IsMatchingMnemonic(LPMSG lpMsg)
{
// return IsAccelerator(m_ctlInfo.hAccel, m_ctlInfo.cAccel, lpMsg, NULL);
if ((m_ctlInfo.cAccel == 0) || (m_ctlInfo.hAccel == NULL))
return FALSE;
ACCEL* pAccel = new ACCEL[m_ctlInfo.cAccel];
int cAccel = CopyAcceleratorTable(m_ctlInfo.hAccel, pAccel, m_ctlInfo.cAccel);
ASSERT(cAccel == m_ctlInfo.cAccel);
BOOL bMatch = FALSE;
for (int i = 0; i < cAccel; i++)
{
BOOL fVirt = (lpMsg->message == WM_SYSCHAR ? FALT : 0);
WORD key = LOWORD(lpMsg->wParam);
if (((pAccel[i].fVirt & ~FNOINVERT) == fVirt) &&
(pAccel[i].key == key))
{
bMatch = TRUE;
break;
}
}
delete [] pAccel;
return bMatch;
}
void COleControlSite::SendMnemonic(LPMSG lpMsg)
{
if (!(m_dwMiscStatus & OLEMISC_NOUIACTIVATE))
SetFocus();
LPOLECONTROL pOleCtl = NULL;
if (SUCCEEDED(m_pObject->QueryInterface(IID_IOleControl,
(LPVOID*)&pOleCtl)))
{
ASSERT(pOleCtl != NULL);
pOleCtl->OnMnemonic(lpMsg);
pOleCtl->Release();
}
}
void COleControlSite::FreezeEvents(BOOL bFreeze)
{
LPOLECONTROL pOleCtl = NULL;
if (SUCCEEDED(m_pObject->QueryInterface(IID_IOleControl,
(LPVOID*)&pOleCtl)))
{
ASSERT(pOleCtl != NULL);
pOleCtl->FreezeEvents(bFreeze);
pOleCtl->Release();
}
}
void COleControlSite::AttachWindow()
{
HWND hWnd = NULL;
if (SUCCEEDED(m_pInPlaceObject->GetWindow(&hWnd)))
{
ASSERT(hWnd != NULL);
if (m_hWnd != hWnd)
{
m_hWnd = hWnd;
if (m_pWndCtrl != NULL)
{
ASSERT(m_pWndCtrl->m_hWnd == NULL); // Window already attached?
m_pWndCtrl->Attach(m_hWnd);
ASSERT(m_pWndCtrl->m_pCtrlSite == NULL ||
m_pWndCtrl->m_pCtrlSite == this);
m_pWndCtrl->m_pCtrlSite = this;
}
}
}
}
void COleControlSite::DetachWindow()
{
m_hWnd = NULL;
if (m_pWndCtrl != NULL)
{
if (m_pWndCtrl->m_hWnd != NULL)
{
WNDPROC* lplpfn = m_pWndCtrl->GetSuperWndProcAddr();
ASSERT(lplpfn != NULL);
if (::IsWindow(m_pWndCtrl->m_hWnd) && *lplpfn != NULL)
m_pWndCtrl->UnsubclassWindow();
m_pWndCtrl->Detach();
}
m_pWndCtrl->m_pCtrlSite = NULL;
}
}
BOOL COleControlSite::OnEvent(AFX_EVENT* pEvent)
{
// If this control has a proxy CWnd, look for a matching ON_*_REFLECT
// entry for this event in its event map.
if ((m_pWndCtrl != NULL) &&
m_pWndCtrl->OnCmdMsg(m_nID, CN_EVENT, pEvent, NULL))
{
return TRUE;
}
// Proxy CWnd isn't interested, so pass the event along to the container.
return m_pCtrlCont->m_pWnd->OnCmdMsg(m_nID, CN_EVENT, pEvent, NULL);
}
/////////////////////////////////////////////////////////////////////////////
// invoke helpers
void COleControlSite::InvokeHelperV(DISPID dwDispID, WORD wFlags,
VARTYPE vtRet, void* pvRet, const BYTE* pbParamInfo, va_list argList)
{
if (m_dispDriver.m_lpDispatch == NULL)
{
// no dispatch pointer yet; find it now
LPDISPATCH pDispatch;
if ((m_pObject != NULL) &&
SUCCEEDED(m_pObject->QueryInterface(IID_IDispatch,
(LPVOID*)&pDispatch)))
{
ASSERT(pDispatch != NULL);
m_dispDriver.AttachDispatch(pDispatch);
}
}
if (m_dispDriver.m_lpDispatch == NULL)
{
// couldn't find dispatch pointer
TRACE0("Warning: control has no IDispatch interface.");
return;
}
// delegate call to m_dispDriver
m_dispDriver.InvokeHelperV(dwDispID, wFlags, vtRet, pvRet, pbParamInfo,
argList);
}
void COleControlSite::SetPropertyV(DISPID dwDispID, VARTYPE vtProp, va_list argList)
{
BYTE rgbParams[2];
if (vtProp & VT_BYREF)
{
vtProp &= ~VT_BYREF;
vtProp |= VT_MFCBYREF;
}
#if !defined(_UNICODE) && !defined(OLE2ANSI)
if (vtProp == VT_BSTR)
vtProp = VT_BSTRA;
#endif
WORD wFlags;
if (vtProp & VT_MFCFORCEPUTREF)
{
wFlags = DISPATCH_PROPERTYPUTREF;
vtProp &= ~VT_MFCFORCEPUTREF;
}
else
{
if (vtProp == VT_DISPATCH)
wFlags = DISPATCH_PROPERTYPUTREF;
else
wFlags = DISPATCH_PROPERTYPUT;
}
rgbParams[0] = (BYTE)vtProp;
rgbParams[1] = 0;
InvokeHelperV(dwDispID, wFlags, VT_EMPTY, NULL, rgbParams, argList);
}
void AFX_CDECL COleControlSite::InvokeHelper(DISPID dwDispID, WORD wFlags, VARTYPE vtRet,
void* pvRet, const BYTE* pbParamInfo, ...)
{
va_list argList;
va_start(argList, pbParamInfo);
InvokeHelperV(dwDispID, wFlags, vtRet, pvRet, pbParamInfo, argList);
va_end(argList);
}
void COleControlSite::GetProperty(DISPID dwDispID, VARTYPE vtProp,
void* pvProp) const
{
const_cast<COleControlSite*>(this)->InvokeHelper(dwDispID,
DISPATCH_PROPERTYGET, vtProp, pvProp, NULL);
}
void AFX_CDECL COleControlSite::SetProperty(DISPID dwDispID, VARTYPE vtProp, ...)
{
va_list argList; // really only one arg, but...
va_start(argList, vtProp);
SetPropertyV(dwDispID, vtProp, argList);
va_end(argList);
}
BOOL AFX_CDECL COleControlSite::SafeSetProperty(DISPID dwDispID, VARTYPE vtProp, ...)
{
va_list argList; // really only one arg, but...
va_start(argList, vtProp);
BOOL bSuccess;
TRY
{
SetPropertyV(dwDispID, vtProp, argList);
bSuccess = TRUE;
}
CATCH_ALL(e)
{
DELETE_EXCEPTION(e);
bSuccess = FALSE;
}
END_CATCH_ALL
va_end(argList);
return bSuccess;
}
/////////////////////////////////////////////////////////////////////////////
// special cases for CWnd functions
DWORD COleControlSite::GetStyle() const
{
DWORD dwStyle = m_dwStyle |
(::GetWindowLong(m_hWnd, GWL_STYLE) & WS_VISIBLE);
TRY
{
BOOL bEnabled = TRUE;
GetProperty(DISPID_ENABLED, VT_BOOL, &bEnabled);
if (!bEnabled)
dwStyle |= WS_DISABLED;
}
END_TRY
TRY
{
short sBorderStyle = 0;
GetProperty(DISPID_BORDERSTYLE, VT_I2, &sBorderStyle);
if (sBorderStyle == 1)
dwStyle |= WS_BORDER;
}
END_TRY
return dwStyle;
}
DWORD COleControlSite::GetExStyle() const
{
DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);
TRY
{
short sAppearance = 0;
GetProperty(DISPID_APPEARANCE, VT_I2, &sAppearance);
if (sAppearance == 1)
dwExStyle |= WS_EX_CLIENTEDGE;
}
END_TRY
return dwExStyle;
}
BOOL COleControlSite::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
m_dwStyle = ((m_dwStyle & ~dwRemove) | dwAdd) & m_dwStyleMask;
// Enabled property
if ((dwRemove & WS_DISABLED) || (dwAdd & WS_DISABLED))
{
if (SafeSetProperty(DISPID_ENABLED, VT_BOOL, (~dwAdd & WS_DISABLED)))
{
dwRemove &= ~WS_DISABLED;
dwAdd &= ~WS_DISABLED;
}
}
// BorderStyle property
if ((dwRemove & WS_BORDER) || (dwAdd & WS_BORDER))
{
if (SafeSetProperty(DISPID_BORDERSTYLE, VT_I2, (dwAdd & WS_BORDER)))
{
dwRemove &= ~WS_BORDER;
dwAdd &= ~WS_BORDER;
}
}
return CWnd::ModifyStyle(m_hWnd, dwRemove, dwAdd, nFlags);
}
BOOL COleControlSite::ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
// BorderStyle property
if ((dwRemove & WS_EX_CLIENTEDGE) || (dwAdd & WS_EX_CLIENTEDGE))
{
if (SafeSetProperty(DISPID_APPEARANCE, VT_I2, (dwAdd & WS_EX_CLIENTEDGE)))
{
dwRemove &= ~WS_EX_CLIENTEDGE;
dwAdd &= ~WS_EX_CLIENTEDGE;
}
}
return CWnd::ModifyStyleEx(m_hWnd, dwRemove, dwAdd, nFlags);
}
void COleControlSite::SetWindowText(LPCTSTR lpszString)
{
ASSERT(::IsWindow(m_hWnd));
if (!SafeSetProperty(DISPID_CAPTION, VT_BSTR, lpszString))
SafeSetProperty(DISPID_TEXT, VT_BSTR, lpszString);
}
void COleControlSite::GetWindowText(CString& str) const
{
ASSERT(::IsWindow(m_hWnd));
TRY
{
GetProperty(DISPID_CAPTION, VT_BSTR, &str);
}
CATCH_ALL(e)
{
DELETE_EXCEPTION(e);
TRY
{
GetProperty(DISPID_TEXT, VT_BSTR, &str);
}
END_TRY
}
END_CATCH_ALL
}
int COleControlSite::GetWindowText(LPTSTR lpszString, int nMaxCount) const
{
ASSERT(nMaxCount > 0);
CString str;
GetWindowText(str);
lstrcpyn(lpszString, str, nMaxCount);
return lstrlen(lpszString);
}
int COleControlSite::GetWindowTextLength() const
{
CString str;
GetWindowText(str);
return str.GetLength();
}
int COleControlSite::GetDlgCtrlID() const
{
return (int)m_nID;
}
int COleControlSite::SetDlgCtrlID(int nID)
{
int nPrevID = (int)m_nID;
m_nID = (UINT)nID;
return nPrevID;
}
void COleControlSite::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL)
{
ASSERT(m_pInPlaceObject != NULL);
ASSERT(m_pObject != NULL);
CRect rectOld(m_rect);
m_rect.SetRect(x, y, x + nWidth, y + nHeight);
if (SetExtent())
{
m_rect.SetRect(x, y, x + m_rect.Width(), y + m_rect.Height());
m_pInPlaceObject->SetObjectRects(m_rect, m_rect);
}
else
{
m_rect = rectOld;
}
}
BOOL COleControlSite::SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx,
int cy, UINT nFlags)
{
if (nFlags & SWP_HIDEWINDOW)
ShowWindow(SW_HIDE);
if ((nFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
{
int xNew;
int yNew;
if (nFlags & SWP_NOMOVE)
{
xNew = m_rect.left;
yNew = m_rect.top;
}
else
{
xNew = x;
yNew = y;
}
int cxNew;
int cyNew;
if (nFlags & SWP_NOSIZE)
{
cxNew = m_rect.Width();
cyNew = m_rect.Height();
}
else
{
cxNew = cx;
cyNew = cy;
}
MoveWindow(xNew, yNew, cxNew, cyNew, !(nFlags & SWP_NOREDRAW));
}
if (nFlags & SWP_SHOWWINDOW)
ShowWindow(SW_SHOW);
// we've handled hide, move, size, and show; let Windows do the rest
nFlags &= ~(SWP_HIDEWINDOW|SWP_SHOWWINDOW);
nFlags |= (SWP_NOMOVE|SWP_NOSIZE);
return ::SetWindowPos(m_hWnd, pWndInsertAfter->GetSafeHwnd(),
x, y, cx, cy, nFlags);
}
BOOL COleControlSite::ShowWindow(int nCmdShow)
{
BOOL bReturn = ::IsWindowVisible(m_hWnd);
int iVerb = 0;
switch (nCmdShow)
{
case SW_SHOW:
case SW_SHOWNORMAL:
case SW_SHOWNOACTIVATE:
iVerb = OLEIVERB_SHOW;
break;
case SW_HIDE:
iVerb = OLEIVERB_HIDE;
break;
}
if (iVerb != 0)
DoVerb(iVerb);
return bReturn;
}
BOOL COleControlSite::IsWindowEnabled() const
{
BOOL bEnabled = TRUE;
TRY
GetProperty(DISPID_ENABLED, VT_BOOL, &bEnabled);
END_TRY
return bEnabled;
}
BOOL COleControlSite::EnableWindow(BOOL bEnable)
{
BOOL bResult;
TRY
{
GetProperty(DISPID_ENABLED, VT_BOOL, &bResult);
SetProperty(DISPID_ENABLED, VT_BOOL, bEnable);
}
CATCH_ALL(e)
{
DELETE_EXCEPTION(e);
bResult = TRUE;
}
END_CATCH_ALL
return !bResult; // return TRUE if previously disabled
}
CWnd* COleControlSite::SetFocus()
{
if (m_dwMiscStatus & OLEMISC_NOUIACTIVATE)
return CWnd::FromHandle(::SetFocus(m_hWnd));
CWnd* pWndPrev = CWnd::GetFocus();
DoVerb(OLEIVERB_UIACTIVATE);
return pWndPrev;
}
void COleControlSite::EnableDSC()
{
if (m_pDataSourceControl == NULL)
{
m_pDataSourceControl = new CDataSourceControl(this);
m_pDataSourceControl->Initialize();
}
}
void COleControlSite::BindDefaultProperty(DISPID dwDispID, VARTYPE vtProp, LPCTSTR szFieldName, CWnd* pDSCWnd)
{
// Remove any previous binding
if (m_pDSCSite != NULL)
{
m_pDSCSite->m_pDataSourceControl->BindProp(this, FALSE);
m_pDSCSite->m_pDataSourceControl->BindColumns();
m_pDSCSite = NULL;
}
if (pDSCWnd != NULL)
{
ASSERT(pDSCWnd->m_pCtrlSite); // must be an OLE control
pDSCWnd->m_pCtrlSite->EnableDSC();
m_pDSCSite = pDSCWnd->m_pCtrlSite;
m_defdispid = dwDispID;
m_dwType = vtProp;
m_strDataField = szFieldName;
m_pDSCSite->m_pDataSourceControl->BindProp(this, TRUE);
if (m_pDSCSite != NULL)
m_pDSCSite->m_pDataSourceControl->BindColumns();
}
}
void COleControlSite::BindProperty(DISPID dwDispId, CWnd* pWndDSC)
{
ASSERT(pWndDSC == NULL || pWndDSC->m_pCtrlSite);
if (pWndDSC != NULL && dwDispId != DISPID_UNKNOWN)
{
m_pBindings = new CDataBoundProperty(m_pBindings, dwDispId, 0);
m_pBindings->m_pDSCSite = pWndDSC->m_pCtrlSite;
m_pBindings->m_pClientSite = this;
m_pBindings->m_pDSCSite->EnableDSC();
m_pBindings->m_pDSCSite->m_pDataSourceControl->BindProp(m_pBindings, TRUE);
}
else
{
// Try and locate the particular property to unbind
// if dwDispId == DISPID_UNKNOWN && pWndDSC == NULL it unbinds all properties
// if dwDispId == DISPID_UNKNOWN && pWndDSC != NULL it unbinds properties for that DSC
CDataBoundProperty *pCurrent = m_pBindings;
CDataBoundProperty* pPrev = NULL;
while (pCurrent != NULL)
{
CDataBoundProperty* pNext = pCurrent->GetNext();
if (dwDispId == DISPID_UNKNOWN || pCurrent->m_dispid == dwDispId)
{
if (pWndDSC == NULL || pWndDSC->m_pCtrlSite == pCurrent->m_pDSCSite)
{
if (pPrev != NULL)
pPrev->m_pNext = pNext;
else
m_pBindings = pNext;
if (pCurrent->m_pDSCSite != NULL && pCurrent->m_pDSCSite->m_pDataSourceControl != NULL)
pCurrent->m_pDSCSite->m_pDataSourceControl->BindProp(pCurrent, FALSE);
delete pCurrent;
}
}
if (pPrev != NULL)
pPrev = pPrev->GetNext();
pCurrent = pNext;
}
}
}
/////////////////////////////////////////////////////////////////////////////
// COleControlSite::XOleClientSite
STDMETHODIMP_(ULONG) COleControlSite::XOleClientSite::AddRef()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleClientSite)
return (ULONG)pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) COleControlSite::XOleClientSite::Release()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleClientSite)
return (ULONG)pThis->InternalRelease();
}
STDMETHODIMP COleControlSite::XOleClientSite::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleControlSite, OleClientSite)
return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleControlSite::XOleClientSite::SaveObject()
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XOleClientSite::GetMoniker(DWORD, DWORD,
LPMONIKER*)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XOleClientSite::GetContainer(
LPOLECONTAINER* ppContainer)
{
METHOD_PROLOGUE_EX_(COleControlSite, OleClientSite)
return (HRESULT)pThis->m_pCtrlCont->InternalQueryInterface(
&IID_IOleContainer, (LPVOID*)ppContainer);
}
STDMETHODIMP COleControlSite::XOleClientSite::ShowObject()
{
METHOD_PROLOGUE_EX(COleControlSite, OleClientSite)
pThis->AttachWindow();
return S_OK;
}
STDMETHODIMP COleControlSite::XOleClientSite::OnShowWindow(BOOL)
{
return S_OK;
}
STDMETHODIMP COleControlSite::XOleClientSite::RequestNewObjectLayout()
{
return E_NOTIMPL;
}
/////////////////////////////////////////////////////////////////////////////
// COleControlSite::XOleIPSite
STDMETHODIMP_(ULONG) COleControlSite::XOleIPSite::AddRef()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
return (ULONG)pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) COleControlSite::XOleIPSite::Release()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
return (ULONG)pThis->InternalRelease();
}
STDMETHODIMP COleControlSite::XOleIPSite::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleControlSite::XOleIPSite::GetWindow(HWND* phWnd)
{
METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
*phWnd = pThis->m_pCtrlCont->m_pWnd->GetSafeHwnd();
return *phWnd != NULL ? S_OK : E_FAIL;
}
STDMETHODIMP COleControlSite::XOleIPSite::ContextSensitiveHelp(BOOL)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XOleIPSite::CanInPlaceActivate()
{
return S_OK;
}
STDMETHODIMP COleControlSite::XOleIPSite::OnInPlaceActivate()
{
return S_OK;
}
STDMETHODIMP COleControlSite::XOleIPSite::OnUIActivate()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
pThis->m_pCtrlCont->OnUIActivate(pThis);
return S_OK;
}
STDMETHODIMP COleControlSite::XOleIPSite::GetWindowContext(
LPOLEINPLACEFRAME* ppFrame, LPOLEINPLACEUIWINDOW* ppDoc, LPRECT prectPos,
LPRECT prectClip, LPOLEINPLACEFRAMEINFO pFrameInfo)
{
METHOD_PROLOGUE_EX(COleControlSite, OleIPSite)
ASSERT_VALID(pThis->m_pCtrlCont);
ASSERT_VALID(pThis->m_pCtrlCont->m_pWnd);
ASSERT(AfxIsValidAddress(ppFrame, sizeof(LPOLEINPLACEFRAME)));
ASSERT((ppDoc == NULL) ||
AfxIsValidAddress(ppDoc, sizeof(LPOLEINPLACEUIWINDOW)));
ASSERT(AfxIsValidAddress(prectPos, sizeof(RECT)));
ASSERT(AfxIsValidAddress(prectClip, sizeof(RECT)));
ASSERT(AfxIsValidAddress(pFrameInfo, pFrameInfo->cb));
//WINBUG: This is a temporary patch for IE3 beta. When IE3 is fixed, this
// assert can be re-enabled. Otherwise it fires everytime you browse via
// the CWebBrowser control.
//
// ASSERT(pFrameInfo->cb >= offsetof(OLEINPLACEFRAMEINFO, cAccelEntries) +
// sizeof(int));
// There is no separate doc window
if (ppDoc != NULL)
*ppDoc = NULL;
// Set pointer to frame
if (FAILED(pThis->m_pCtrlCont->InternalQueryInterface(
&IID_IOleInPlaceFrame, (LPVOID*)ppFrame)))
return E_FAIL;
// Fill in position and clip rectangles
CWnd* pWndContainer = pThis->m_pCtrlCont->m_pWnd;
CopyRect(prectPos, pThis->m_rect);
pWndContainer->GetClientRect(prectClip);
// Fill in frame info
pFrameInfo->fMDIApp = FALSE;
pFrameInfo->hwndFrame = pWndContainer->GetSafeHwnd();
pFrameInfo->haccel = NULL;
pFrameInfo->cAccelEntries = 0;
return S_OK;
}
STDMETHODIMP COleControlSite::XOleIPSite::Scroll(SIZE)
{
return S_FALSE;
}
STDMETHODIMP COleControlSite::XOleIPSite::OnUIDeactivate(BOOL)
{
METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
pThis->m_pCtrlCont->OnUIDeactivate(pThis);
return S_OK;
}
STDMETHODIMP COleControlSite::XOleIPSite::OnInPlaceDeactivate()
{
METHOD_PROLOGUE_EX(COleControlSite, OleIPSite)
pThis->DetachWindow();
return S_OK;
}
STDMETHODIMP COleControlSite::XOleIPSite::DiscardUndoState()
{
return S_OK;
}
STDMETHODIMP COleControlSite::XOleIPSite::DeactivateAndUndo()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
pThis->m_pInPlaceObject->UIDeactivate();
return S_OK;
}
STDMETHODIMP COleControlSite::XOleIPSite::OnPosRectChange(LPCRECT lprcPosRect)
{
METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
CRect rectClip;
pThis->m_pCtrlCont->m_pWnd->GetClientRect(rectClip);
pThis->m_rect = lprcPosRect;
return pThis->m_pInPlaceObject->SetObjectRects(pThis->m_rect, rectClip);
}
/////////////////////////////////////////////////////////////////////////////
// COleControlSite::XOleControlSite
STDMETHODIMP_(ULONG) COleControlSite::XOleControlSite::AddRef()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
return (ULONG)pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) COleControlSite::XOleControlSite::Release()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
return (ULONG)pThis->InternalRelease();
}
STDMETHODIMP COleControlSite::XOleControlSite::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleControlSite::XOleControlSite::OnControlInfoChanged()
{
METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
pThis->GetControlInfo();
return NOERROR;
}
STDMETHODIMP COleControlSite::XOleControlSite::LockInPlaceActive(BOOL)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XOleControlSite::GetExtendedControl(
LPDISPATCH*)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XOleControlSite::TransformCoords(
POINTL* pptHimetric, POINTF* pptContainer, DWORD dwFlags)
{
METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
HRESULT hr = NOERROR;
HDC hDC = ::GetDC(pThis->m_hWnd);
::SetMapMode(hDC, MM_HIMETRIC);
POINT rgptConvert[2];
rgptConvert[0].x = 0;
rgptConvert[0].y = 0;
if (dwFlags & XFORMCOORDS_HIMETRICTOCONTAINER)
{
rgptConvert[1].x = pptHimetric->x;
rgptConvert[1].y = pptHimetric->y;
::LPtoDP(hDC, rgptConvert, 2);
if (dwFlags & XFORMCOORDS_SIZE)
{
pptContainer->x = (float)(rgptConvert[1].x - rgptConvert[0].x);
pptContainer->y = (float)(rgptConvert[0].y - rgptConvert[1].y);
}
else if (dwFlags & XFORMCOORDS_POSITION)
{
pptContainer->x = (float)rgptConvert[1].x;
pptContainer->y = (float)rgptConvert[1].y;
}
else
{
hr = E_INVALIDARG;
}
}
else if (dwFlags & XFORMCOORDS_CONTAINERTOHIMETRIC)
{
rgptConvert[1].x = (int)(pptContainer->x);
rgptConvert[1].y = (int)(pptContainer->y);
::DPtoLP(hDC, rgptConvert, 2);
if (dwFlags & XFORMCOORDS_SIZE)
{
pptHimetric->x = rgptConvert[1].x - rgptConvert[0].x;
pptHimetric->y = rgptConvert[0].y - rgptConvert[1].y;
}
else if (dwFlags & XFORMCOORDS_POSITION)
{
pptHimetric->x = rgptConvert[1].x;
pptHimetric->y = rgptConvert[1].y;
}
else
{
hr = E_INVALIDARG;
}
}
else
{
hr = E_INVALIDARG;
}
::ReleaseDC(pThis->m_hWnd, hDC);
return hr;
}
STDMETHODIMP COleControlSite::XOleControlSite::TranslateAccelerator(
LPMSG, DWORD)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XOleControlSite::OnFocus(BOOL)
{
return S_OK;
}
STDMETHODIMP COleControlSite::XOleControlSite::ShowPropertyFrame()
{
return E_NOTIMPL;
}
/////////////////////////////////////////////////////////////////////////////
// COleControlSite::XAmbientProps
STDMETHODIMP_(ULONG) COleControlSite::XAmbientProps::AddRef()
{
METHOD_PROLOGUE_EX_(COleControlSite, AmbientProps)
return (ULONG)pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) COleControlSite::XAmbientProps::Release()
{
METHOD_PROLOGUE_EX_(COleControlSite, AmbientProps)
return (ULONG)pThis->InternalRelease();
}
STDMETHODIMP COleControlSite::XAmbientProps::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleControlSite, AmbientProps)
return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleControlSite::XAmbientProps::GetTypeInfoCount(
unsigned int*)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XAmbientProps::GetTypeInfo(
unsigned int, LCID, ITypeInfo**)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XAmbientProps::GetIDsOfNames(
REFIID, LPOLESTR*, unsigned int, LCID, DISPID*)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XAmbientProps::Invoke(
DISPID dispid, REFIID, LCID, unsigned short wFlags,
DISPPARAMS* pDispParams, VARIANT* pvarResult,
EXCEPINFO*, unsigned int*)
{
UNUSED(wFlags);
UNUSED(pDispParams);
METHOD_PROLOGUE_EX(COleControlSite, AmbientProps)
ASSERT(wFlags & DISPATCH_PROPERTYGET);
ASSERT(pDispParams->cArgs == 0);
ASSERT(pThis->m_pCtrlCont != NULL);
ASSERT(pThis->m_pCtrlCont->m_pWnd != NULL);
return pThis->m_pCtrlCont->m_pWnd->OnAmbientProperty(pThis, dispid, pvarResult) ?
S_OK : DISP_E_MEMBERNOTFOUND;
}
/////////////////////////////////////////////////////////////////////////////
// COleControlSite::XPropertyNotifySink
STDMETHODIMP COleControlSite::XPropertyNotifySink::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleControlSite, PropertyNotifySink)
if (IsEqualIID(iid, IID_IUnknown) ||
IsEqualIID(iid, IID_IPropertyNotifySink))
{
*ppvObj = this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) COleControlSite::XPropertyNotifySink::AddRef()
{
return 1;
}
STDMETHODIMP_(ULONG) COleControlSite::XPropertyNotifySink::Release()
{
return 0;
}
STDMETHODIMP COleControlSite::XPropertyNotifySink::OnChanged(
DISPID dispid)
{
METHOD_PROLOGUE_EX(COleControlSite, PropertyNotifySink)
// If we are currently updating the control ignore notifications
if (pThis->m_bIgnoreNotify)
return S_OK;
// Give user chance to override
if (!pThis->m_pDataSourceControl)
{
AFX_EVENT event(AFX_EVENT::propChanged, dispid);
pThis->OnEvent(&event);
if (event.m_hResult != S_OK)
return event.m_hResult;
}
if (pThis->m_defdispid == dispid)
{
::VariantClear(&pThis->m_varResult);
HRESULT hRes;
LPDISPATCH pDispatch = NULL;
hRes = pThis->m_pObject->QueryInterface(IID_IDispatch, (LPVOID *) &pDispatch);
if (FAILED(hRes))
return S_OK;
EXCEPINFO excepinfo;
memset(&excepinfo, 0, sizeof(EXCEPINFO));
UINT uArgErr;
DISPPARAMS dispparamsGetProp;
memset (&dispparamsGetProp, 0, sizeof(DISPPARAMS));
hRes = pDispatch->Invoke(dispid, IID_NULL, 0, INVOKE_PROPERTYGET, &dispparamsGetProp,
&pThis->m_varResult, &excepinfo, &uArgErr); //Get bound control property
if (excepinfo.bstrSource)
SysFreeString(excepinfo.bstrSource);
if (excepinfo.bstrDescription)
SysFreeString(excepinfo.bstrDescription);
if (excepinfo.bstrHelpFile)
SysFreeString(excepinfo.bstrHelpFile);
pDispatch->Release();
if (FAILED(hRes))
return S_OK;
pThis->m_bIsDirty = TRUE;
}
return S_OK;
}
STDMETHODIMP COleControlSite::XPropertyNotifySink::OnRequestEdit(
DISPID dispid)
{
METHOD_PROLOGUE_EX(COleControlSite, PropertyNotifySink)
// If we are currently updating the control ignore notifications
if (pThis->m_bIgnoreNotify)
return S_OK;
// If not bound fire regular MFC event
if (!pThis->m_pDataSourceControl)
{
AFX_EVENT event(AFX_EVENT::propRequest, dispid);
pThis->OnEvent(&event);
if (event.m_hResult != S_OK)
return event.m_hResult;
}
// Currently we only support Optimistic binding ala VB4
// In this model, requests always succeed
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// COleControlSite::XEventSink
STDMETHODIMP_(ULONG) COleControlSite::XEventSink::AddRef()
{
return 1;
}
STDMETHODIMP_(ULONG) COleControlSite::XEventSink::Release()
{
return 0;
}
STDMETHODIMP COleControlSite::XEventSink::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleControlSite, EventSink)
if (IsEqualIID(iid, IID_IUnknown) ||
IsEqualIID(iid, IID_IDispatch) ||
IsEqualIID(iid, pThis->m_iidEvents))
{
*ppvObj = this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP COleControlSite::XEventSink::GetTypeInfoCount(
unsigned int*)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XEventSink::GetTypeInfo(
unsigned int, LCID, ITypeInfo**)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XEventSink::GetIDsOfNames(
REFIID, LPOLESTR*, unsigned int, LCID, DISPID*)
{
return E_NOTIMPL;
}
STDMETHODIMP COleControlSite::XEventSink::Invoke(
DISPID dispid, REFIID, LCID, unsigned short wFlags,
DISPPARAMS* pDispParams, VARIANT* pvarResult,
EXCEPINFO* pExcepInfo, unsigned int* puArgError)
{
UNUSED(wFlags);
METHOD_PROLOGUE_EX(COleControlSite, EventSink)
ASSERT(pThis->m_pCtrlCont != NULL);
ASSERT(pThis->m_pCtrlCont->m_pWnd != NULL);
ASSERT(wFlags == DISPATCH_METHOD);
AFX_EVENT event(AFX_EVENT::event, dispid, pDispParams, pExcepInfo,
puArgError);
pThis->OnEvent(&event);
if (pvarResult != NULL)
::VariantClear(pvarResult);
return event.m_hResult;
}
/////////////////////////////////////////////////////////////////////////////
// CDataSourceControl
CDataSourceControl::CDataSourceControl(COleControlSite *pClientSite) :
m_pClientSite(pClientSite),
m_pCursorMove(NULL),
m_pCursorUpdateARow(NULL),
m_pMetaRowData(NULL),
m_pVarData(NULL),
m_nColumns(0),
m_nBindings(0),
m_pColumnBindings(NULL),
m_pValues(NULL),
m_bUpdateInProgress(FALSE),
m_pDataSource(NULL),
m_pRowPosition(NULL),
m_pRowset(NULL),
m_pDynamicAccessor(NULL),
m_dwRowsetNotify(0)
{
ASSERT(pClientSite);
}
CDataSourceControl::~CDataSourceControl()
{
// cancel ole/db notifications
if (m_dwRowsetNotify != 0 && m_pRowset != NULL)
{
LPCONNECTIONPOINTCONTAINER pConnPtCont;
if (SUCCEEDED(m_pRowset->m_spRowset->QueryInterface(IID_IConnectionPointContainer,
(LPVOID*)&pConnPtCont)))
{
ASSERT(pConnPtCont != NULL);
LPCONNECTIONPOINT pConnPt = NULL;
if (SUCCEEDED(pConnPtCont->FindConnectionPoint(IID_IRowsetNotify, &pConnPt)))
{
ASSERT(pConnPt != NULL);
pConnPt->Unadvise(m_dwRowsetNotify);
pConnPt->Release();
}
pConnPtCont->Release();
}
}
// Now go through all cursor bound properties
while (!m_CursorBoundProps.IsEmpty())
{
CDataBoundProperty* pProp = (CDataBoundProperty*) m_CursorBoundProps.GetHead();
pProp->m_pClientSite->BindProperty(pProp->m_dispid, NULL);
pProp->m_pClientSite->m_pDSCSite = NULL;
}
m_CursorBoundProps.RemoveAll();
if (m_pValues)
{
for (int i=0; i<m_nBindings; i++)
::VariantClear(&m_pValues[i]);
if (m_nBindings)
{
delete[] m_pColumnBindings;
delete[] m_pValues;
}
}
if (m_pCursorMove)
m_pCursorMove->Release();
if (m_pCursorUpdateARow)
m_pCursorUpdateARow->Release();
if (m_pMetaRowData)
{
for (int nCol=0; nCol<m_nColumns; nCol++)
{
POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
while (pos)
{
COleControlSite* pSite = (COleControlSite *)
m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
pSite->m_pDSCSite = NULL;
}
m_pMetaRowData[nCol].m_pClientList->RemoveAll();
delete m_pMetaRowData[nCol].m_pClientList;
}
::CoTaskMemFree(m_pMetaRowData);
}
if (m_pVarData)
::CoTaskMemFree(m_pVarData);
if(m_pDynamicAccessor != NULL)
{
m_pDynamicAccessor->ReleaseAccessors(m_pRowset->m_spRowset);
m_pDynamicAccessor->Close();
}
delete m_pDynamicAccessor;
delete m_pRowset;
if (m_pRowPosition != NULL)
m_pRowPosition->Release();
if (m_pDataSource != NULL)
m_pDataSource->Release();
}
interface IVBDSC : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE CancelUnload(BOOL __RPC_FAR* pfCancel) = 0;
virtual HRESULT STDMETHODCALLTYPE Error(DWORD dwErr, BOOL __RPC_FAR* pfShowError) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateCursor(ICursor __RPC_FAR* __RPC_FAR* ppCursor) = 0;
};
const IID IID_IVBDSC = {0x1ab42240,0x8c70,0x11ce,{0x94,0x21,0x0,0xaa,0x0,0x62,0xbe,0x57}};
const IID CLSID_DataAdapter = {0x3A08E130L,0x8F65,0x11D0,{0x94,0x84,0x00,0xA0,0xC9,0x11,0x10,0xED}};
HRESULT CDataSourceControl::Initialize()
{
// The following is a work around for RDC behaviour when on an invisible dlg
// When the dlg is invisible it cannot display the ODBC connect dialog
// So check if visible, if not make it so and move it to the center
// of the screen with null size. Then do the connect dialog
// Finally put it all back like it was.
CWnd* pParent = m_pClientSite->m_pWndCtrl->GetTopLevelParent();
BOOL bHidden = !pParent->IsWindowVisible();
CRect rcParent;
if (bHidden)
{
CRect rcDesktop;
CWnd::GetDesktopWindow()->GetWindowRect(&rcDesktop);
pParent->GetWindowRect(&rcParent);
pParent->MoveWindow((rcDesktop.right - rcDesktop.left)/2, (rcDesktop.bottom - rcDesktop.top)/2, 0, 0, FALSE);
pParent->ShowWindow(SW_SHOWNORMAL);
}
IVBDSC* pDSC;
HRESULT hRes;
hRes = m_pClientSite->m_pObject->QueryInterface(IID_IDataSource, (void**)&m_pDataSource);
if (SUCCEEDED(hRes))
{
hRes = m_pDataSource->GetDataMember(NULL, &IID_IRowPosition, (IUnknown**)&m_pRowPosition);
if (m_pRowPosition == NULL)
hRes = E_POINTER;
if (FAILED(hRes))
{
if (bHidden)
{
pParent->MoveWindow(rcParent.left, rcParent.top, rcParent.right - rcParent.left, rcParent.bottom - rcParent.top, FALSE);
pParent->ShowWindow(SW_HIDE);
}
return hRes;
}
}
else
{
hRes = m_pClientSite->m_pObject->QueryInterface(IID_IVBDSC, (void**)&pDSC);
if (FAILED(hRes))
return hRes;
ICursor* pCursor;
pDSC->CreateCursor(&pCursor);
pDSC->Release();
if (!pCursor)
return E_FAIL;
hRes = pCursor->QueryInterface(IID_ICursorMove,
(LPVOID *)&m_pCursorMove);
pCursor->Release();
if (FAILED(hRes))
return hRes;
hRes = m_pCursorMove->QueryInterface(IID_ICursorUpdateARow,
(LPVOID *)&m_pCursorUpdateARow);
}
hRes = GetMetaData();
if (bHidden)
{
pParent->MoveWindow(rcParent.left, rcParent.top, rcParent.right - rcParent.left, rcParent.bottom - rcParent.top, FALSE);
pParent->ShowWindow(SW_HIDE);
}
return hRes;
}
IUnknown* CDataSourceControl::GetCursor()
{
ASSERT(m_pClientSite != NULL);
if (m_pDataSource != NULL)
{
if(m_pRowset != NULL)
return m_pDataSource;
return NULL;
}
ICursor* pCursor;
if (!m_pCursorMove)
{
IVBDSC* pDSC;
HRESULT hRes;
hRes = m_pClientSite->m_pObject->QueryInterface(IID_IVBDSC, (void**)&pDSC);
if (FAILED(hRes))
return NULL;
pDSC->CreateCursor(&pCursor);
pDSC->Release();
if (!pCursor)
return NULL;
return pCursor;
}
if (SUCCEEDED(m_pCursorMove->QueryInterface(IID_ICursor, (LPVOID *) &pCursor)))
return pCursor;
ASSERT(FALSE); // DSC Cursor Not Found
return NULL;
}
HRESULT CDataSourceControl::GetMetaData()
{
HRESULT hRes;
METAROWTYPE* pOldMetaData = m_pMetaRowData;
int nOldColumns = m_nColumns;
if (m_pDataSource != NULL)
{
IRowset* pRowset;
hRes = m_pRowPosition->GetRowset(IID_IRowset, reinterpret_cast<IUnknown**>(&pRowset));
if (FAILED(hRes))
return hRes;
{
LPCONNECTIONPOINTCONTAINER pConnPtCont;
if (SUCCEEDED(pRowset->QueryInterface(IID_IConnectionPointContainer,
(LPVOID*)&pConnPtCont)))
{
ASSERT(pConnPtCont != NULL);
LPCONNECTIONPOINT pConnPt = NULL;
if (SUCCEEDED(pConnPtCont->FindConnectionPoint(IID_IRowsetNotify, &pConnPt)))
{
ASSERT(pConnPt != NULL);
pConnPt->Advise(&m_pClientSite->m_xRowsetNotify, &m_dwRowsetNotify);
pConnPt->Release();
}
pConnPtCont->Release();
}
}
m_pRowset = new CRowset(pRowset);
pRowset->Release();
m_pRowset->SetupOptionalRowsetInterfaces();
m_pDynamicAccessor = new CDynamicAccessor;
m_pDynamicAccessor->BindColumns(m_pRowset->m_spRowset);
m_pRowset->SetAccessor(m_pDynamicAccessor);
m_nColumns = m_pDynamicAccessor->GetColumnCount();
m_pMetaRowData = (METAROWTYPE*)::CoTaskMemAlloc(sizeof(METAROWTYPE) * m_nColumns);
ASSERT(m_pMetaRowData);
memset(m_pMetaRowData, 0, sizeof(METAROWTYPE) * m_nColumns);
m_pRowset->MoveFirst();
m_pRowset->ReleaseRows();
}
else
{
ULONG nRows;
ICursor* pCursor = (LPCURSOR)m_pCursorMove;
ICursor* pColumnCursor;
if (pCursor == NULL)
return S_OK;
hRes = pCursor->GetColumnsCursor(IID_ICursor, (IUnknown **) &pColumnCursor, &nRows);
if (FAILED(hRes))
return hRes;
DBCOLUMNBINDING MetaColumns[2];
CopyColumnID(&MetaColumns[0].columnID, &COLUMN_COLUMNID);
MetaColumns[0].obData = offsetof(METAROWTYPE, idColumnID);
MetaColumns[0].cbMaxLen = DB_NOMAXLENGTH;
MetaColumns[0].obInfo = offsetof(METAROWTYPE, dwColumnID);
MetaColumns[0].obVarDataLen = DB_NOVALUE;
MetaColumns[0].dwBinding = DBBINDING_DEFAULT;
MetaColumns[0].dwDataType = DBTYPE_COLUMNID;
CopyColumnID(&MetaColumns[1].columnID, &COLUMN_NAME);
MetaColumns[1].obData = offsetof(METAROWTYPE, lpstrName);
MetaColumns[1].cbMaxLen = DB_NOMAXLENGTH;
MetaColumns[1].obInfo = offsetof(METAROWTYPE, dwName);
MetaColumns[1].obVarDataLen = DB_NOVALUE;
MetaColumns[1].dwBinding = DBBINDING_DEFAULT;
MetaColumns[1].dwDataType = VT_LPSTR;
hRes = pColumnCursor->SetBindings(2, MetaColumns, sizeof(METAROWTYPE),
DBCOLUMNBINDOPTS_REPLACE);
if (FAILED(hRes))
{
pColumnCursor->Release();
return hRes;
}
DBFETCHROWS FetchRows;
FetchRows.cRowsRequested = nRows;
FetchRows.dwFlags = DBROWFETCH_CALLEEALLOCATES;
FetchRows.pData = NULL;
FetchRows.pVarData = NULL;
FetchRows.cbVarData = 0;
LARGE_INTEGER dlZero;
LISet32(dlZero, 0);
hRes = pColumnCursor->GetNextRows(dlZero, &FetchRows);
if (FAILED(hRes))
{
pColumnCursor->Release();
return hRes;
}
m_pMetaRowData = (METAROWTYPE *)FetchRows.pData;
ASSERT(m_pMetaRowData);
nRows = FetchRows.cRowsReturned; // in case it changed
m_pVarData = FetchRows.pVarData;
m_nColumns = nRows;
pColumnCursor->Release();
}
for (int nCol=0; nCol<m_nColumns; nCol++)
m_pMetaRowData[nCol].m_pClientList = new CPtrList;
// re-establish all bound property sites and then delete old meta-data
if (pOldMetaData != NULL)
{
for (int nCol=0; nCol<nOldColumns; nCol++)
{
POSITION pos = pOldMetaData[nCol].m_pClientList->GetHeadPosition();
while (pos)
{
COleControlSite* pSite = (COleControlSite *)
m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
BindProp(pSite, TRUE);
}
pOldMetaData[nCol].m_pClientList->RemoveAll();
delete pOldMetaData[nCol].m_pClientList;
}
::CoTaskMemFree(pOldMetaData);
}
return hRes;
}
BOOL CDataSourceControl::CopyColumnID(
DBCOLUMNID* pcidDst, DBCOLUMNID const *pcidSrc)
{
pcidDst->dwKind = pcidSrc->dwKind;
switch (pcidSrc->dwKind)
{
case DBCOLKIND_GUID_NUMBER:
pcidDst->guid = pcidSrc->guid;
pcidDst->lNumber = pcidSrc->lNumber;
break;
case DBCOLKIND_GUID_NAME:
pcidDst->guid = pcidSrc->guid;
// fall through
case DBCOLKIND_NAME:
pcidDst->lpdbsz = (LPDBSTR) ::CoTaskMemAlloc(sizeof(DBCHAR) * (ldbstrlen(pcidSrc->lpdbsz) + 1));
if (!pcidDst->lpdbsz)
return FALSE;
ldbstrcpy(pcidDst->lpdbsz, pcidSrc->lpdbsz);
break;
}
return TRUE;
}
// Make a bound control/bound property a consumer to a particular column in this DSC
void CDataSourceControl::BindProp(COleControlSite* pClientSite, BOOL bBind)
{
ASSERT(pClientSite);
if (bBind)
{
BindProp(pClientSite, FALSE);
ASSERT(pClientSite->m_pDSCSite == m_pClientSite);
if (m_pDataSource != NULL)
{
for (int nCol=0; nCol<m_nColumns; nCol++)
{
if (pClientSite->m_strDataField == m_pDynamicAccessor->GetColumnName(nCol + 1))
{
m_pMetaRowData[nCol].m_pClientList->AddTail(pClientSite);
return;
}
}
}
else
{
for (int nCol=0; nCol<m_nColumns; nCol++)
{
if (m_pMetaRowData[nCol].lpstrName == NULL)
continue;
if (pClientSite->m_strDataField == m_pMetaRowData[nCol].lpstrName)
{
m_pMetaRowData[nCol].m_pClientList->AddTail(pClientSite);
return;
}
}
}
pClientSite->m_pDSCSite = NULL;
return;
}
UpdateCursor();
// UnBind
for (int nCol=0; nCol<m_nColumns; nCol++)
{
POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
POSITION prev;
while (pos)
{
prev = pos;
COleControlSite* pSite = (COleControlSite *)
m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
if (pSite == pClientSite)
{
m_pMetaRowData[nCol].m_pClientList->RemoveAt(prev);
return;
}
}
}
}
// Make a cursor bound control property a client to this control
void CDataSourceControl::BindProp(CDataBoundProperty* pProperty, BOOL bBind)
{
ASSERT(pProperty);
if (bBind)
{
BindProp(pProperty, FALSE);
m_CursorBoundProps.AddTail(pProperty);
}
else
{
UpdateCursor();
POSITION pos = m_CursorBoundProps.Find(pProperty);
if (pos != NULL)
m_CursorBoundProps.RemoveAt(pos);
}
}
void CDataSourceControl::BindColumns()
{
if (m_pDataSource != NULL)
{
// this is done automatically by CDynamicAccessor
GetBoundClientRow();
UpdateControls();
return;
}
if (m_pValues)
{
for (int i=0; i<m_nBindings; i++)
::VariantClear(&m_pValues[i]);
if (m_nBindings > 0)
{
delete[] m_pValues;
delete[] m_pColumnBindings;
}
m_pValues = NULL;
}
m_nBindings = 0;
for (int nCol=0; nCol<m_nColumns; nCol++)
{
m_nBindings += m_pMetaRowData[nCol].m_pClientList->GetCount();
}
if (m_nBindings > 0)
m_pColumnBindings = new DBCOLUMNBINDING[m_nBindings];
int nItem = 0;
for (nCol=0; nCol<m_nColumns; nCol++)
{
POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
while (pos)
{
COleControlSite* pSite = (COleControlSite *)
m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
CopyColumnID(&m_pColumnBindings[nItem].columnID, &m_pMetaRowData[nCol].idColumnID);
m_pColumnBindings[nItem].obData = sizeof(VARIANT) * nItem;
m_pColumnBindings[nItem].cbMaxLen = DB_NOMAXLENGTH;
m_pColumnBindings[nItem].obInfo = DB_NOVALUE;
m_pColumnBindings[nItem].obVarDataLen = DB_NOVALUE;
m_pColumnBindings[nItem].dwBinding = DBBINDING_VARIANT;
m_pColumnBindings[nItem].dwDataType = pSite->m_dwType;
nItem++;
}
}
m_pCursorMove->SetBindings(m_nBindings, m_pColumnBindings,
sizeof(VARIANT) * m_nBindings, DBCOLUMNBINDOPTS_REPLACE);
if (m_nBindings)
m_pValues = new VARIANT[m_nBindings];
for (int i=0; i<m_nBindings; i++)
{
memset(&m_pValues[i], 0, sizeof(VARIANT));
m_pValues[i].vt = VT_EMPTY;
}
GetBoundClientRow();
UpdateControls();
}
HRESULT CDataSourceControl::GetBoundClientRow()
{
DBFETCHROWS FetchRows;
if (m_pDataSource != NULL)
{
if(m_pRowset == NULL)
return S_OK;
if(m_pRowset->m_hRow == NULL)
return S_OK;
return m_pRowset->GetData();
}
if (m_nBindings == 0)
return S_OK;
FetchRows.pData = m_pValues;
FetchRows.pVarData = NULL;
FetchRows.cbVarData = NULL;
FetchRows.cRowsRequested = 1;
FetchRows.dwFlags = 0;
LARGE_INTEGER dl = { 0, 0};
return m_pCursorMove->Move(1, (LPVOID)&DBBMK_CURRENT, dl, &FetchRows);
}
COleVariant CDataSourceControl::ToVariant(int nCol)
{
ASSERT(m_pDataSource != NULL);
ASSERT(m_pDynamicAccessor != NULL);
COleVariant vt;
DBSTATUS dbStatus;
DBTYPE dbType;
m_pDynamicAccessor->GetStatus(nCol, &dbStatus);
if(dbStatus == DBSTATUS_S_ISNULL)
return vt; // just return a blank variant
if(!m_pDynamicAccessor->GetColumnType(nCol, &dbType))
return vt;
switch (dbType)
{
case DBTYPE_VARIANT:
vt = COleVariant((LPCVARIANT)m_pDynamicAccessor->GetValue(nCol));
break;
case DBTYPE_STR:
vt = COleVariant(CString((LPCSTR)m_pDynamicAccessor->GetValue(nCol)), VT_BSTR);
break;
case DBTYPE_WSTR:
case DBTYPE_BSTR:
vt = COleVariant(CString((LPCWSTR)m_pDynamicAccessor->GetValue(nCol)), VT_BSTR);
break;
case DBTYPE_I1:
case DBTYPE_UI1:
vt = COleVariant(*((BYTE*)m_pDynamicAccessor->GetValue(nCol)));
break;
case DBTYPE_I2:
case DBTYPE_UI2:
vt = COleVariant(*((short*)m_pDynamicAccessor->GetValue(nCol)));
break;
case DBTYPE_I4:
case DBTYPE_UI4:
vt = COleVariant(*((long*)m_pDynamicAccessor->GetValue(nCol)));
break;
case DBTYPE_R4:
vt = COleVariant(*((float*)m_pDynamicAccessor->GetValue(nCol)));
break;
case DBTYPE_R8:
vt = COleVariant(*((double*)m_pDynamicAccessor->GetValue(nCol)));
break;
case DBTYPE_BOOL:
vt = COleVariant((short)*(BOOL*)m_pDynamicAccessor->GetValue(nCol), VT_BOOL);
break;
case DBTYPE_DATE:
{
COleDateTime dt(*((DATE*)m_pDynamicAccessor->GetValue(nCol)));
vt = COleVariant(dt);
}
break;
case DBTYPE_CY:
{
COleCurrency cy(*((CURRENCY*)m_pDynamicAccessor->GetValue(nCol)));
vt = COleVariant(cy);
}
break;
case DBTYPE_NUMERIC:
{
DB_NUMERIC num;
if(m_pDynamicAccessor->GetValue(nCol, &num))
{
double dbl;
dbl = (double)*((__int64*)num.val);
while(num.scale-- > 0)
dbl /= 10;
if(num.sign == 0)
dbl = -dbl;
vt = COleVariant(dbl);
}
}
break;
case DBTYPE_DBDATE:
{
DBDATE dbDate;
if(m_pDynamicAccessor->GetValue(nCol, &dbDate))
{
COleDateTime dt;
dt.SetDate(dbDate.year, dbDate.month, dbDate.day);
vt = COleVariant(dt);
}
}
break;
case DBTYPE_DBTIME:
{
DBTIME dbTime;
if(m_pDynamicAccessor->GetValue(nCol, &dbTime))
{
COleDateTime dt;
dt.SetTime(dbTime.hour, dbTime.minute, dbTime.second);
vt = COleVariant(dt);
}
}
break;
case DBTYPE_DBTIMESTAMP:
{
DBTIMESTAMP dbTimeStamp;
if(m_pDynamicAccessor->GetValue(nCol, &dbTimeStamp))
{
vt = COleVariant(COleDateTime(dbTimeStamp.year, dbTimeStamp.month, dbTimeStamp.day,
dbTimeStamp.hour, dbTimeStamp.minute, dbTimeStamp.second));
}
}
break;
case DBTYPE_NULL:
case DBTYPE_EMPTY:
break;
default:
TRACE2("Unsupported DBTYPE (%d) in column %d\n", dbType, nCol);
break;
}
return vt;
}
HRESULT CDataSourceControl::UpdateControls()
{
m_bUpdateInProgress = TRUE;
int nItem = 0;
for (int nCol=0; nCol<m_nColumns; nCol++)
{
POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
while (pos)
{
COleControlSite* pSite = (COleControlSite *)
m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
DISPPARAMS dispparamsSetProp;
DISPID dispidNamed = DISPID_PROPERTYPUT;
EXCEPINFO excepinfo;
memset(&excepinfo, 0, sizeof(EXCEPINFO));
UINT uArgErr;
COleVariant vt;
if (m_pDataSource != NULL)
{
vt = ToVariant(nCol + 1);
dispparamsSetProp.rgvarg = &vt;
}
else
{
dispparamsSetProp.rgvarg = &m_pValues[nItem];
}
dispparamsSetProp.rgdispidNamedArgs = &dispidNamed;
dispparamsSetProp.cArgs = 1;
dispparamsSetProp.cNamedArgs = 1;
HRESULT hRes;
LPDISPATCH pDispatch;
pSite->m_bIgnoreNotify = TRUE;
if (pSite->m_pObject == NULL)
continue;
hRes = pSite->m_pObject->QueryInterface(IID_IDispatch, (LPVOID *) &pDispatch);
if (FAILED(hRes))
continue;
hRes = pDispatch->Invoke(pSite->m_defdispid, IID_NULL, 0, INVOKE_PROPERTYPUT, &dispparamsSetProp,
NULL, &excepinfo, &uArgErr); //Set the bound control property
pDispatch->Release();
pSite->m_bIgnoreNotify = FALSE;
if (excepinfo.bstrSource)
SysFreeString(excepinfo.bstrSource);
if (excepinfo.bstrDescription)
SysFreeString(excepinfo.bstrDescription);
if (excepinfo.bstrHelpFile)
SysFreeString(excepinfo.bstrHelpFile);
vt.Clear();
nItem++;
}
}
m_bUpdateInProgress = FALSE;
return S_OK;
}
HRESULT CDataSourceControl::UpdateCursor()
{
HRESULT hRes;
int nVariant = 0;
int nDirtyField = 0;
if (m_pDataSource != NULL)
{
if(m_pDynamicAccessor == NULL)
return S_OK;
// First go through all simple bound properties
for (int nCol=1; nCol<=m_nColumns; nCol++)
{
POSITION pos = m_pMetaRowData[nCol - 1].m_pClientList->GetHeadPosition();
while (pos)
{
COleControlSite* pSite = (COleControlSite *)
m_pMetaRowData[nCol - 1].m_pClientList->GetNext(pos);
DBTYPE dbType;
if (pSite->m_bIsDirty)
{
pSite->m_bIsDirty = FALSE;
nDirtyField++;
if (nDirtyField == 1)
{
// UpdateinProgress semaphore - unexpected state
ASSERT(!m_bUpdateInProgress);
m_bUpdateInProgress = TRUE;
}
COleVariant var(pSite->m_varResult);
CManualAccessor accessor;
// Create accessor for output column
accessor.CreateAccessor(1, m_pDynamicAccessor->GetValue(nCol), m_pDynamicAccessor->m_pColumnInfo[nCol].ulColumnSize);
accessor.AddBindEntry(m_pDynamicAccessor->m_pColumnInfo[nCol].iOrdinal,
m_pDynamicAccessor->m_pColumnInfo[nCol].wType,
m_pDynamicAccessor->m_pColumnInfo[nCol].ulColumnSize,
m_pDynamicAccessor->GetValue(nCol));
accessor.BindColumns(m_pRowset->m_spRowset);
VERIFY(m_pDynamicAccessor->GetColumnType(nCol, &dbType));
switch(dbType)
{
case DBTYPE_I2:
var.ChangeType(VT_I2);
m_pDynamicAccessor->SetValue(nCol, var.iVal);
break;
case DBTYPE_I4:
var.ChangeType(VT_I4);
m_pDynamicAccessor->SetValue(nCol, var.lVal);
break;
case DBTYPE_R4:
var.ChangeType(VT_R4);
m_pDynamicAccessor->SetValue(nCol, var.fltVal);
break;
case DBTYPE_R8:
var.ChangeType(VT_R8);
m_pDynamicAccessor->SetValue(nCol, var.dblVal);
break;
case DBTYPE_CY:
var.ChangeType(VT_CY);
*(CY*)m_pDynamicAccessor->GetValue(nCol) = var.cyVal;
break;
case DBTYPE_DATE:
var.ChangeType(VT_DATE);
m_pDynamicAccessor->SetValue(nCol, var.date);
break;
case DBTYPE_BSTR:
case DBTYPE_WSTR:
var.ChangeType(VT_BSTR);
wcsncpy((wchar_t*)m_pDynamicAccessor->GetValue(nCol), var.bstrVal, m_pDynamicAccessor->m_pColumnInfo[nCol].ulColumnSize);
break;
case DBTYPE_BOOL:
var.ChangeType(VT_BOOL);
m_pDynamicAccessor->SetValue(nCol, var.boolVal);
break;
case DBTYPE_DECIMAL:
var.ChangeType(VT_DECIMAL);
m_pDynamicAccessor->SetValue(nCol, var.decVal);
break;
case DBTYPE_UI1:
var.ChangeType(VT_UI1);
m_pDynamicAccessor->SetValue(nCol, var.bVal);
break;
case DBTYPE_I1:
var.ChangeType(VT_I1);
m_pDynamicAccessor->SetValue(nCol, (signed char)var.cVal);
break;
case DBTYPE_UI2:
var.ChangeType(VT_UI2);
m_pDynamicAccessor->SetValue(nCol, var.uiVal);
break;
case DBTYPE_UI4:
var.ChangeType(VT_UI4);
m_pDynamicAccessor->SetValue(nCol, var.ulVal);
break;
case DBTYPE_STR:
var.ChangeType(VT_BSTR);
WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, (char*)m_pDynamicAccessor->GetValue(nCol),
m_pDynamicAccessor->m_pColumnInfo[nCol].ulColumnSize, NULL, NULL);
break;
case DBTYPE_DBTIMESTAMP:
DBTIMESTAMP ts;
SYSTEMTIME sysTime;
var.ChangeType(VT_DATE);
memset(&ts, 0, sizeof(DBTIMESTAMP));
VariantTimeToSystemTime(var.date, &sysTime);
ts.year = sysTime.wYear;
ts.month = sysTime.wMonth;
ts.day = sysTime.wDay;
ts.hour = sysTime.wHour;
ts.minute = sysTime.wMinute;
ts.second = sysTime.wSecond;
ts.fraction = sysTime.wMilliseconds / 1000000;
m_pDynamicAccessor->SetValue(nCol, ts);
break;
default:
TRACE2("Unsupported DBTYPE (%d) in column %d\n", dbType, nCol);
break;
}
m_pRowset->SetAccessor(&accessor);
m_pRowset->SetData();
m_pRowset->SetAccessor(m_pDynamicAccessor);
::VariantClear(&pSite->m_varResult);
}
nVariant++;
}
}
if (nDirtyField > 0)
{
m_bUpdateInProgress = FALSE;
}
return S_OK;
}
// Do we have an updateable cursor?
if (m_pCursorUpdateARow == NULL)
{
// If not attempt to get one
hRes = m_pCursorMove->QueryInterface(IID_ICursorUpdateARow,
(LPVOID *)&m_pCursorUpdateARow);
if (FAILED(hRes))
return S_OK; // no update cursor, so forget updating
}
// First go through all simple bound properties
for (int nCol=0; nCol<m_nColumns; nCol++)
{
POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
while (pos)
{
COleControlSite* pSite = (COleControlSite *)
m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
if (pSite->m_bIsDirty)
{
pSite->m_bIsDirty = FALSE;
nDirtyField++;
if (nDirtyField == 1)
{
DWORD dwEdit;
hRes = m_pCursorUpdateARow->GetEditMode(&dwEdit);
if (FAILED(hRes))
return hRes;
if (dwEdit == DBEDITMODE_NONE)
{
hRes = m_pCursorUpdateARow->BeginUpdate(DBROWACTION_UPDATE);
if (FAILED(hRes))
return hRes;
}
// UpdateinProgress semaphore - unexpected state
ASSERT(!m_bUpdateInProgress);
m_bUpdateInProgress = TRUE;
}
DBBINDPARAMS bpBindParams;
DWORD dwIndicator = sizeof(VARIANT);
COleVariant vt;
switch (V_VT(&pSite->m_varResult))
{
case VT_EMPTY:
case VT_NULL:
case VT_ERROR:
dwIndicator = DB_NULL;
vt = pSite->m_varResult;
break;
case VT_BSTR:
if(*pSite->m_varResult.bstrVal == 0)
{
dwIndicator = DB_NULL;
break;
}
default:
vt = pSite->m_varResult;
break;
}
bpBindParams.cbMaxLen = 0L;
bpBindParams.dwBinding = DBBINDING_VARIANT;
bpBindParams.dwDataType = m_pColumnBindings[nVariant].dwDataType;
bpBindParams.cbVarDataLen = 0L;
bpBindParams.dwInfo = dwIndicator;
bpBindParams.pData = &vt;
hRes = m_pCursorUpdateARow->SetColumn(&m_pColumnBindings[nVariant].columnID, &bpBindParams);
::VariantClear(&pSite->m_varResult);
}
nVariant++;
}
}
// Now go through all cursor bound properties
POSITION pos = m_CursorBoundProps.GetHeadPosition();
while (pos != NULL)
{
CDataBoundProperty* pProp = (CDataBoundProperty*) m_CursorBoundProps.GetNext(pos);
if (pProp->m_pClientSite->m_pObject == NULL)
continue;
IBoundObject *pBO;
if (SUCCEEDED(pProp->m_pClientSite->m_pObject->QueryInterface(IID_IBoundObject,
(LPVOID *) &pBO)))
{
if (pBO->IsDirty(pProp->m_dispid) == S_OK)
{
nDirtyField++;
if (nDirtyField == 1)
{
DWORD dwEdit;
hRes = m_pCursorUpdateARow->GetEditMode(&dwEdit);
if (FAILED(hRes))
return hRes;
if (dwEdit == DBEDITMODE_NONE)
{
hRes = m_pCursorUpdateARow->BeginUpdate(DBROWACTION_UPDATE);
if (FAILED(hRes))
return hRes;
}
// UpdateinProgress semaphore - unexpected state
ASSERT(!m_bUpdateInProgress);
m_bUpdateInProgress = TRUE;
}
}
pBO->Release();
}
}
if (nDirtyField > 0)
{
hRes = m_pCursorUpdateARow->Update(0,0,0);
m_bUpdateInProgress = FALSE;
if (FAILED(hRes))
{
// Update failed w/dirty controls
ASSERT(hRes!= S_OK);
UpdateControls();
return hRes;
}
}
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CDataBoundProperty Handles Databound Controls
CDataBoundProperty::CDataBoundProperty(CDataBoundProperty* pLast, DISPID dispid, WORD ctlid) :
m_dispid(dispid),
m_ctlid(ctlid),
m_pClientSite(NULL),
m_pDSCSite(NULL),
m_bIsDirty(FALSE),
m_pNext(pLast)
{
}
void CDataBoundProperty::SetClientSite(COleControlSite *pClientSite)
{
m_pClientSite = pClientSite;
}
// (Re)bind a cursor bound property to a DSC
void CDataBoundProperty::SetDSCSite(COleControlSite *pDSCSite)
{
if (m_pDSCSite == pDSCSite)
return;
m_pDSCSite = pDSCSite;
Notify();
}
CDataBoundProperty* CDataBoundProperty::GetNext()
{
return m_pNext;
}
void CDataBoundProperty::RemoveSource()
{
m_pDSCSite = NULL;
Notify();
}
void CDataBoundProperty::Notify()
{
if (m_dispid != DISPID_DATASOURCE)
{
IBoundObject *pBO;
if (m_pClientSite != NULL)
{
if (SUCCEEDED(m_pClientSite->m_pObject->QueryInterface(IID_IBoundObject,
(LPVOID *) &pBO)))
{
pBO->OnSourceChanged(m_dispid, m_pDSCSite != NULL, &m_bOwnXferOut);
pBO->Release();
}
else
{
IUnknown* pUnk = GetCursor();
if (pUnk != NULL)
{
VARTYPE vt = VT_UNKNOWN;
if (m_pDSCSite->m_pDataSourceControl != NULL)
vt |= VT_MFCFORCEPUTREF;
m_pClientSite->SetProperty(m_dispid, vt, pUnk);
}
}
}
}
}
IUnknown* CDataBoundProperty::GetCursor()
{
if(m_pDSCSite == NULL)
return NULL;
m_pDSCSite->EnableDSC();
ASSERT(m_pDSCSite->m_pDataSourceControl);
m_pDSCSite->m_pDataSourceControl->BindProp(this);
return m_pDSCSite->m_pDataSourceControl->GetCursor();
}
/////////////////////////////////////////////////////////////////////////////
// COleControlSite::XBoundObjectSite
HRESULT COleControlSite::GetCursor(
DISPID dispid, LPUNKNOWN* ppcursorOut, LPVOID *ppcidOut)
{
if (ppcidOut != NULL)
*ppcidOut = NULL;
CDataBoundProperty* pBinding = m_pBindings;
while (pBinding != NULL)
{
if (pBinding->m_dispid == dispid)
{
*ppcursorOut = pBinding->GetCursor();
return S_OK;
}
pBinding = pBinding->GetNext();
}
return S_OK;
}
STDMETHODIMP_(ULONG) COleControlSite::XBoundObjectSite::AddRef()
{
METHOD_PROLOGUE_EX(COleControlSite, BoundObjectSite)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) COleControlSite::XBoundObjectSite::Release()
{
METHOD_PROLOGUE_EX(COleControlSite, BoundObjectSite)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP COleControlSite::XBoundObjectSite::QueryInterface(
REFIID iid, LPVOID far * ppvObj)
{
METHOD_PROLOGUE_EX(COleControlSite, BoundObjectSite)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleControlSite::XBoundObjectSite::GetCursor(
DISPID dispid, LPLPCURSOR ppcursorOut, LPVOID *ppcidOut)
{
METHOD_PROLOGUE_EX(COleControlSite, BoundObjectSite)
return pThis->GetCursor(dispid, (LPUNKNOWN*)ppcursorOut, ppcidOut);
}
/////////////////////////////////////////////////////////////////////////////
// COleControlSite::XNotifyDBEvents
STDMETHODIMP_(ULONG) COleControlSite::XNotifyDBEvents::AddRef()
{
return 1;
}
STDMETHODIMP_(ULONG) COleControlSite::XNotifyDBEvents::Release()
{
return 0;
}
STDMETHODIMP COleControlSite::XNotifyDBEvents::QueryInterface(
REFIID iid, LPVOID far * ppvObj)
{
METHOD_PROLOGUE_EX_(COleControlSite, NotifyDBEvents)
if (IsEqualIID(iid, IID_IUnknown) ||
IsEqualIID(iid, IID_INotifyDBEvents))
{
*ppvObj = this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP COleControlSite::XNotifyDBEvents::OKToDo(
DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
{
METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
dscOKToDo);
if (FAILED(hRes))
return hRes;
DWORD reason = rgReasons[0].dwReason;
if (reason == DBREASON_SETCOLUMN ||
reason == DBREASON_INSERTED ||
reason == DBREASON_MODIFIED)
return S_OK;
// Mask out all notifications except as currency changes and update
if (!(dwEventWhat & DBEVENT_CURRENT_ROW_CHANGED) &&
reason != DBREASON_INSERTED &&
reason != DBREASON_MODIFIED &&
reason != DBREASON_DELETED &&
reason != DBREASON_ADDNEW)
return S_OK;
CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
if (pDSC == NULL)
return S_OK;
if (!(dwEventWhat & DBEVENT_CURRENT_ROW_CHANGED))
return S_OK;
return pDSC->UpdateCursor();
}
STDMETHODIMP COleControlSite::XNotifyDBEvents::Cancelled(
DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
{
METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
dscCancelled);
if (FAILED(hRes))
return hRes;
return S_OK;
}
STDMETHODIMP COleControlSite::XNotifyDBEvents::SyncBefore(
DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
{
METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
dscSyncBefore);
if (FAILED(hRes))
return hRes;
DWORD reason = rgReasons[0].dwReason;
// Mask out all notifications except as shown
if (reason != DBREASON_INSERTED &&
reason != DBREASON_MODIFIED &&
reason != DBREASON_ADDNEW)
return S_OK;
CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
if (pDSC == NULL)
return S_OK;
if (dwEventWhat & DBEVENT_METADATA_CHANGED)
{
pDSC->UpdateCursor();
}
return S_OK;
}
STDMETHODIMP COleControlSite::XNotifyDBEvents::AboutToDo(
DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
{
METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
dscAboutToDo);
if (FAILED(hRes))
return hRes;
return S_OK;
}
STDMETHODIMP COleControlSite::XNotifyDBEvents::FailedToDo(
DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
{
METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
dscFailedToDo);
if (FAILED(hRes))
return hRes;
return S_OK;
}
STDMETHODIMP COleControlSite::XNotifyDBEvents::SyncAfter(
DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
{
METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
dscSyncAfter);
if (FAILED(hRes))
return hRes;
DWORD reason = rgReasons[0].dwReason;
CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
if (pDSC == NULL)
return S_OK;
//Check semaphore - don't want to collect data during Update if it was due to a Move (it's a NOP!)
if (pDSC->m_bUpdateInProgress ||
reason == DBREASON_EDIT ||
reason == DBREASON_SETCOLUMN)
return S_OK;
//Mask out all notifications except as shown
if (!(dwEventWhat & (DBEVENT_CURRENT_ROW_CHANGED | DBEVENT_CURRENT_ROW_DATA_CHANGED)))
return S_OK;
if (reason != DBREASON_INSERTED &&
reason != DBREASON_MODIFIED)
{
BOOL bUpdateInProgress = pDSC->m_bUpdateInProgress;
pDSC->m_bUpdateInProgress = TRUE;
pDSC->GetBoundClientRow();
pDSC->m_bUpdateInProgress = bUpdateInProgress;
pDSC->UpdateControls();
}
return S_OK;
}
STDMETHODIMP COleControlSite::XNotifyDBEvents::DidEvent(
DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
{
METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
dscDidEvent);
if (FAILED(hRes))
return hRes;
CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
if (pDSC == NULL)
return S_OK;
if (dwEventWhat & DBEVENT_METADATA_CHANGED)
{
BOOL bUpdateInProgress = pDSC->m_bUpdateInProgress;
pDSC->m_bUpdateInProgress = TRUE;
pDSC->GetBoundClientRow();
pDSC->m_bUpdateInProgress = bUpdateInProgress;
pDSC->UpdateControls();
}
return S_OK;
}
HRESULT COleControlSite::XNotifyDBEvents::FireEvent(
DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[], DSCSTATE nState)
{
METHOD_PROLOGUE_EX_(COleControlSite, NotifyDBEvents)
if (dwEventWhat & DBEVENT_CURRENT_ROW_CHANGED
|| dwEventWhat & DBEVENT_CURRENT_ROW_DATA_CHANGED)
{
for (UINT i=0; i<cReasons; i++)
{
DSCREASON nReason = dscNoReason;
switch (rgReasons[i].dwReason)
{
case DBREASON_CLOSE:
nReason = dscClose;
break;
case DBREASON_FIND:
case DBREASON_MOVE:
case DBREASON_MOVEPERCENT:
case DBREASON_NEWINDEX:
case DBREASON_NEWPARAMETERS:
case DBREASON_QUERYSPECCHANGED:
case DBREASON_REFRESH:
case DBREASON_SEEK:
case DBREASON_SETRANGECHANGED:
nReason = dscMove;
break;
case DBREASON_ADDNEW:
case DBREASON_INSERTED:
nReason = dscInsert;
break;
case DBREASON_EDIT:
nReason = dscEdit;
break;
case DBREASON_MODIFIED:
case DBREASON_RECALC:
case DBREASON_ROLLBACK:
case DBREASON_ROWFIXUP:
nReason = dscModify;
break;
case DBREASON_DELETED:
nReason = dscDelete;
break;
case DBREASON_COMMIT:
nReason = dscCommit;
break;
}
if (nReason != dscNoReason)
{
AFX_EVENT event(AFX_EVENT::propDSCNotify);
event.m_nDSCState = nState;
event.m_nDSCReason = nReason;
pThis->OnEvent(&event);
return event.m_hResult;
}
}
return S_OK;
}
return S_OK;
}
STDMETHODIMP_(ULONG) COleControlSite::XRowsetNotify::AddRef()
{
return 1;
}
STDMETHODIMP_(ULONG) COleControlSite::XRowsetNotify::Release()
{
return 0;
}
STDMETHODIMP COleControlSite::XRowsetNotify::QueryInterface(
REFIID iid, LPVOID far * ppvObj)
{
METHOD_PROLOGUE_EX_(COleControlSite, RowsetNotify)
if (IsEqualIID(iid, IID_IUnknown) ||
IsEqualIID(iid, IID_IRowsetNotify))
{
*ppvObj = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP COleControlSite::XRowsetNotify::OnFieldChange(
IRowset* /*pRowset*/, HROW /*hRow*/, ULONG /*cColumns*/, ULONG /*rgColumns*/[],
DBREASON /*eReason*/, DBEVENTPHASE ePhase, BOOL /*fCantDeny*/)
{
METHOD_PROLOGUE_EX(COleControlSite, RowsetNotify)
DSCSTATE nState = dscNoState;
switch(ePhase)
{
case DBEVENTPHASE_OKTODO:
nState = dscOKToDo;
break;
case DBEVENTPHASE_ABOUTTODO:
nState = dscAboutToDo;
break;
case DBEVENTPHASE_SYNCHAFTER:
nState = dscSyncAfter;
break;
case DBEVENTPHASE_FAILEDTODO:
nState = dscFailedToDo;
break;
case DBEVENTPHASE_DIDEVENT:
nState = dscDidEvent;
break;
}
if(nState == dscDidEvent)
{
CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
if (pDSC == NULL)
return S_OK;
if(pDSC->m_bUpdateInProgress == FALSE)
{
ASSERT(pDSC->m_pRowset);
BOOL bUpdateInProgress = pDSC->m_bUpdateInProgress;
pDSC->m_bUpdateInProgress = TRUE;
pDSC->GetBoundClientRow();
pDSC->m_bUpdateInProgress = bUpdateInProgress;
pDSC->UpdateControls();
}
}
AFX_EVENT event(AFX_EVENT::propDSCNotify);
event.m_nDSCState = nState;
event.m_nDSCReason = dscModify;
pThis->OnEvent(&event);
return event.m_hResult;
}
STDMETHODIMP COleControlSite::XRowsetNotify::OnRowChange(
IRowset* /*pRowset*/, ULONG cRows, const HROW rghRows[],
DBREASON eReason, DBEVENTPHASE ePhase, BOOL /*fCantDeny*/)
{
METHOD_PROLOGUE_EX(COleControlSite, RowsetNotify)
HRESULT hRes = S_OK;
DSCSTATE nState = dscNoState;
switch(ePhase)
{
case DBEVENTPHASE_OKTODO:
nState = dscOKToDo;
break;
case DBEVENTPHASE_ABOUTTODO:
nState = dscAboutToDo;
break;
case DBEVENTPHASE_SYNCHAFTER:
nState = dscSyncAfter;
break;
case DBEVENTPHASE_FAILEDTODO:
nState = dscFailedToDo;
break;
case DBEVENTPHASE_DIDEVENT:
nState = dscDidEvent;
break;
}
DSCREASON nReason = dscNoReason;
switch(eReason)
{
case DBREASON_ROW_ACTIVATE:
nReason = dscMove;
break;
case DBREASON_ROW_DELETE:
nReason = dscDelete;
break;
case DBREASON_ROW_INSERT:
nReason = dscInsert;
break;
case DBREASON_ROW_UPDATE:
nReason = dscCommit;
break;
}
CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
if (pDSC == NULL)
return S_OK;
ASSERT(pDSC->m_pRowset);
if (nReason == dscCommit && nState == dscAboutToDo)
{
pDSC->UpdateCursor();
}
else if ((nReason == dscMove && cRows == 1) || (nState == dscSyncAfter && nReason == dscInsert))
{
pDSC->UpdateCursor();
pDSC->m_pRowset->m_hRow = rghRows[0];
BOOL bUpdateInProgress = pDSC->m_bUpdateInProgress;
pDSC->m_bUpdateInProgress = TRUE;
pDSC->GetBoundClientRow();
pDSC->m_bUpdateInProgress = bUpdateInProgress;
if(!pDSC->m_bUpdateInProgress)
pDSC->UpdateControls();
}
if (nReason != dscNoReason)
{
AFX_EVENT event(AFX_EVENT::propDSCNotify);
event.m_nDSCState = nState;
event.m_nDSCReason = nReason;
pThis->OnEvent(&event);
hRes = event.m_hResult;
if(FAILED(hRes))
return hRes;
}
return S_OK;
}
STDMETHODIMP COleControlSite::XRowsetNotify::OnRowsetChange(
IRowset* /*pRowset*/, DBREASON eReason, DBEVENTPHASE /*ePhase*/, BOOL /*fCantDeny*/)
{
METHOD_PROLOGUE_EX(COleControlSite, RowsetNotify)
if(eReason == DBREASON_ROWSET_CHANGED)
{
CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
if (pDSC == NULL)
return S_OK;
ASSERT(pDSC->m_pRowset);
ASSERT(pDSC->m_pDynamicAccessor);
pDSC->m_pDynamicAccessor->ReleaseAccessors(pDSC->m_pRowset->m_spRowset);
pDSC->m_pDynamicAccessor->Close();
pDSC->m_pDynamicAccessor->BindColumns(pDSC->m_pRowset->m_spRowset);
if( pDSC->m_nColumns != (int)pDSC->m_pDynamicAccessor->GetColumnCount() )
{
pDSC->m_nColumns = pDSC->m_pDynamicAccessor->GetColumnCount();
::CoTaskMemFree(pDSC->m_pMetaRowData);
pDSC->m_pMetaRowData = (CDataSourceControl::METAROWTYPE*)::CoTaskMemAlloc(sizeof(CDataSourceControl::METAROWTYPE) * pDSC->m_nColumns);
ASSERT(pDSC->m_pMetaRowData);
memset(pDSC->m_pMetaRowData, 0, sizeof(CDataSourceControl::METAROWTYPE) * pDSC->m_nColumns);
}
}
return S_OK;
}