// 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(&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(&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(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; iRelease(); if (m_pCursorUpdateARow) m_pCursorUpdateARow->Release(); if (m_pMetaRowData) { for (int nCol=0; nColGetHeadPosition(); 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(&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; nColGetHeadPosition(); 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; nColm_strDataField == m_pDynamicAccessor->GetColumnName(nCol + 1)) { m_pMetaRowData[nCol].m_pClientList->AddTail(pClientSite); return; } } } else { for (int nCol=0; nColm_strDataField == m_pMetaRowData[nCol].lpstrName) { m_pMetaRowData[nCol].m_pClientList->AddTail(pClientSite); return; } } } pClientSite->m_pDSCSite = NULL; return; } UpdateCursor(); // UnBind for (int nCol=0; nColGetHeadPosition(); 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 0) { delete[] m_pValues; delete[] m_pColumnBindings; } m_pValues = NULL; } m_nBindings = 0; for (int nCol=0; nColGetCount(); } if (m_nBindings > 0) m_pColumnBindings = new DBCOLUMNBINDING[m_nBindings]; int nItem = 0; for (nCol=0; nColGetHeadPosition(); 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; im_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; nColGetHeadPosition(); 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; nColGetHeadPosition(); 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; iOnEvent(&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; }