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 >
C/C++ Source or Header  |  1998-06-16  |  90KB  |  3,525 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include "occimpl.h"
  13. #include "msdadc.h"
  14.  
  15. #ifdef AFX_OCC_SEG
  16. #pragma code_seg(AFX_OCC_SEG)
  17. #endif
  18.  
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23.  
  24. #define new DEBUG_NEW
  25.  
  26. #define S_QUICKACTIVATED S_FALSE
  27.  
  28. #include "initguid.h"
  29. #define DBINITCONSTANTS
  30. #define INITGUID
  31.  
  32. DEFINE_GUID(IID_IDataSourceListener,0x7C0FFAB2L,0xCD84,0x11D0,0x94,0x9A,0x00,0xA0,0xC9,0x11,0x10,0xED);
  33. DEFINE_GUID(IID_IDataSource,0x7c0ffab3L, 0xcd84, 0x11d0, 0x94, 0x9a, 0x00, 0xa0, 0xc9, 0x11, 0x10, 0xed);
  34.  
  35. /////////////////////////////////////////////////////////////////////////////
  36. // COleControlSite
  37.  
  38. BEGIN_INTERFACE_MAP(COleControlSite, CCmdTarget)
  39.     INTERFACE_PART(COleControlSite, IID_IOleClientSite, OleClientSite)
  40.     INTERFACE_PART(COleControlSite, IID_IOleInPlaceSite, OleIPSite)
  41.     INTERFACE_PART(COleControlSite, IID_IOleControlSite, OleControlSite)
  42.     INTERFACE_PART(COleControlSite, IID_IDispatch, AmbientProps)
  43.     INTERFACE_PART(COleControlSite, IID_IBoundObjectSite, BoundObjectSite)
  44.     INTERFACE_PART(COleControlSite, IID_INotifyDBEvents, NotifyDBEvents)
  45.     INTERFACE_PART(COleControlSite, IID_IRowsetNotify, RowsetNotify)
  46. END_INTERFACE_MAP()
  47.  
  48. COleControlSite::COleControlSite(COleControlContainer* pCtrlCont) :
  49.     m_pCtrlCont(pCtrlCont),
  50.     m_pWndCtrl(NULL),
  51.     m_nID((UINT)-1),
  52.     m_pObject(NULL),
  53.     m_pInPlaceObject(NULL),
  54.     m_pActiveObject(NULL),
  55.     m_dwEventSink(0),
  56.     m_dwPropNotifySink(0),
  57.     m_dwMiscStatus(0),
  58.     m_dwNotifyDBEvents(0),
  59.     m_pDataSourceControl(NULL),
  60.     m_pDSCSite(NULL),
  61.     m_defdispid(0),
  62.     m_dwType(0),
  63.     m_pBindings(NULL),
  64.     m_bIgnoreNotify(FALSE),
  65.     m_bIsDirty(FALSE)
  66. {
  67.     memset(&m_varResult, 0, sizeof(VARIANT));
  68.     m_varResult.vt = VT_EMPTY;
  69. }
  70.  
  71. COleControlSite::~COleControlSite()
  72. {
  73.     delete m_pDataSourceControl;
  74.  
  75.     DetachWindow();
  76.  
  77.     DisconnectSink(m_iidEvents, m_dwEventSink);
  78.     DisconnectSink(IID_IPropertyNotifySink, m_dwPropNotifySink);
  79.     DisconnectSink(IID_INotifyDBEvents, m_dwNotifyDBEvents);
  80.  
  81.     if (m_pInPlaceObject != NULL)
  82.     {
  83.         m_pInPlaceObject->InPlaceDeactivate();
  84.         m_pInPlaceObject->Release();
  85.         m_pInPlaceObject = NULL;
  86.     }
  87.  
  88.     if (m_pActiveObject != NULL)
  89.     {
  90.         m_pActiveObject->Release();
  91.         m_pActiveObject = NULL;
  92.     }
  93.  
  94.     if (m_pObject != NULL)
  95.     {
  96.         m_pObject->SetClientSite(NULL);
  97.         m_pObject->Close(OLECLOSE_NOSAVE);
  98.         m_pObject->Release();
  99.         m_pObject = NULL;
  100.     }
  101.  
  102.     ::VariantClear(&m_varResult);
  103.  
  104.     BindProperty(DISPID_UNKNOWN, NULL);  // gets rid of complex bindings
  105.  
  106.     if (m_defdispid != 0 && m_pDSCSite != NULL &&
  107.         m_pDSCSite->m_pDataSourceControl != NULL)
  108.     {
  109.         // get rid of simple bindings
  110.         m_pDSCSite->m_pDataSourceControl->BindProp(this, FALSE);
  111.     }
  112. }
  113.  
  114. BOOL COleControlSite::SetExtent()
  115. {
  116.     CSize size(m_rect.Size());
  117.     CClientDC dc(NULL);
  118.     dc.DPtoHIMETRIC(&size);
  119.  
  120.     HRESULT hr;
  121.  
  122.     if (SUCCEEDED(hr = m_pObject->SetExtent(DVASPECT_CONTENT, (SIZEL*)&size)))
  123.     {
  124.         if (SUCCEEDED(m_pObject->GetExtent(DVASPECT_CONTENT, (SIZEL*)&size)))
  125.         {
  126.             dc.HIMETRICtoDP(&size);
  127.             m_rect.right = m_rect.left + size.cx;
  128.             m_rect.bottom = m_rect.top + size.cy;
  129.         }
  130.     }
  131.  
  132.     return SUCCEEDED(hr);
  133. }
  134.  
  135. HRESULT COleControlSite::CreateControl(CWnd* pWndCtrl, REFCLSID clsid,
  136.     LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, UINT nID,
  137.     CFile* pPersist, BOOL bStorage, BSTR bstrLicKey)
  138. {
  139.    CRect rect2( rect );
  140.    CPoint pt;
  141.    CSize size;
  142.  
  143.    pt = rect2.TopLeft();
  144.    size = rect2.Size();
  145.  
  146.    return( CreateControl( pWndCtrl, clsid, lpszWindowName, dwStyle, &pt, &size,
  147.       nID, pPersist, bStorage, bstrLicKey ) );
  148. }
  149.  
  150. HRESULT COleControlSite::CreateControl(CWnd* pWndCtrl, REFCLSID clsid,
  151.     LPCTSTR lpszWindowName, DWORD dwStyle, const POINT* ppt, const SIZE* psize,
  152.    UINT nID, CFile* pPersist, BOOL bStorage, BSTR bstrLicKey)
  153. {
  154.     HRESULT hr = E_FAIL;
  155.     m_hWnd = NULL;
  156.    CSize size;
  157.  
  158.     // Connect the OLE Control with its proxy CWnd object
  159.     if (pWndCtrl != NULL)
  160.     {
  161.         ASSERT(pWndCtrl->m_pCtrlSite == NULL);
  162.         m_pWndCtrl = pWndCtrl;
  163.         pWndCtrl->m_pCtrlSite = this;
  164.     }
  165.  
  166.     // Initialize OLE, if necessary
  167.     _AFX_THREAD_STATE* pState = AfxGetThreadState();
  168.     if (!pState->m_bNeedTerm && !AfxOleInit())
  169.         return hr;
  170.  
  171.     if (SUCCEEDED(hr = CreateOrLoad(clsid, pPersist, bStorage, bstrLicKey)))
  172.     {
  173.         ASSERT(m_pObject != NULL);
  174.         m_nID = nID;
  175.  
  176.         if (psize == NULL)
  177.         {
  178.             // If psize is NULL, ask the object how big it wants to be.
  179.             CClientDC dc(NULL);
  180.  
  181.             m_pObject->GetExtent(DVASPECT_CONTENT, &size);
  182.             dc.HIMETRICtoDP(&size);
  183.             m_rect = CRect(*ppt, size);
  184.         }
  185.         else
  186.         {
  187.             m_rect = CRect(*ppt, *psize);
  188.         }
  189.  
  190.         m_dwStyleMask = WS_GROUP | WS_TABSTOP;
  191.  
  192.         if (m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON)
  193.             m_dwStyleMask |= BS_DEFPUSHBUTTON;
  194.  
  195.         if (m_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME)
  196.             dwStyle &= ~WS_VISIBLE;
  197.  
  198.         m_dwStyle = dwStyle & m_dwStyleMask;
  199.  
  200.         // If control wasn't quick-activated, then connect sinks now.
  201.         if (hr != S_QUICKACTIVATED)
  202.         {
  203.             m_dwEventSink = ConnectSink(m_iidEvents, &m_xEventSink);
  204.             m_dwPropNotifySink = ConnectSink(IID_IPropertyNotifySink,
  205.                 &m_xPropertyNotifySink);
  206.         }
  207.         m_dwNotifyDBEvents = ConnectSink(IID_INotifyDBEvents, &m_xNotifyDBEvents);
  208.  
  209.         // Now that the object has been created, attempt to
  210.         // in-place activate it.
  211.  
  212.         SetExtent();
  213.  
  214.         if (SUCCEEDED(hr = m_pObject->QueryInterface(IID_IOleInPlaceObject,
  215.                 (LPVOID*)&m_pInPlaceObject)))
  216.         {
  217.             if (dwStyle & WS_VISIBLE)
  218.             {
  219.                 // control is visible: just activate it
  220.                 hr = DoVerb(OLEIVERB_INPLACEACTIVATE);
  221.             }
  222.             else
  223.             {
  224.                 // control is not visible: activate off-screen, hide, then move
  225.                 m_rect.OffsetRect(-32000, -32000);
  226.                 if (SUCCEEDED(hr = DoVerb(OLEIVERB_INPLACEACTIVATE)) &&
  227.                     SUCCEEDED(hr = DoVerb(OLEIVERB_HIDE)))
  228.                 {
  229.                     m_rect.OffsetRect(32000, 32000);
  230.                     hr = m_pInPlaceObject->SetObjectRects(m_rect, m_rect);
  231.                 }
  232.             }
  233.         }
  234.         else
  235.         {
  236.             TRACE1("IOleInPlaceObject not supported on OLE control (dialog ID %d).\n", nID);
  237.             TRACE1(">>> Result code: 0x%08lx\n", hr);
  238.         }
  239.  
  240.         if (SUCCEEDED(hr))
  241.             GetControlInfo();
  242.  
  243.         // if QueryInterface or activation failed, cleanup everything
  244.         if (FAILED(hr))
  245.         {
  246.             if (m_pInPlaceObject != NULL)
  247.             {
  248.                 m_pInPlaceObject->Release();
  249.                 m_pInPlaceObject = NULL;
  250.             }
  251.             DisconnectSink(m_iidEvents, m_dwEventSink);
  252.             DisconnectSink(IID_IPropertyNotifySink, m_dwPropNotifySink);
  253.             DisconnectSink(IID_INotifyDBEvents, m_dwNotifyDBEvents);
  254.             m_dwEventSink = 0;
  255.             m_dwPropNotifySink = 0;
  256.             m_dwNotifyDBEvents = 0;
  257.             m_pObject->Release();
  258.             m_pObject = NULL;
  259.         }
  260.     }
  261.  
  262.     if (SUCCEEDED(hr))
  263.     {
  264.         AttachWindow();
  265.  
  266.         ASSERT(m_hWnd != NULL);
  267.  
  268.         // Initialize the control's Caption or Text property, if any
  269.         if (lpszWindowName != NULL)
  270.             SetWindowText(lpszWindowName);
  271.  
  272.         // Initialize styles
  273.         ModifyStyle(0, m_dwStyle | (dwStyle & (WS_DISABLED|WS_BORDER)), 0);
  274.     }
  275.  
  276.     return hr;
  277. }
  278.  
  279. BOOL COleControlSite::DestroyControl()
  280. {
  281.     ASSERT(m_hWnd != NULL);     // was control ever successfully created?
  282.     m_pCtrlCont->m_siteMap.RemoveKey(m_hWnd);
  283.  
  284.     //VBBUG: VB controls will crash if IOleObject::Close is called on them
  285.     //  when they have focus (and unfortunately, deactivating them does not
  286.     //  always move the focus).  To work around this problem, we always hide
  287.     //  the control before closing it.
  288.     ShowWindow(SW_HIDE);
  289.  
  290.     // Now it is safe to close the control.
  291.     delete this;
  292.  
  293.     return TRUE;
  294. }
  295.  
  296. AFX_STATIC HRESULT AFXAPI _AfxCoCreateInstanceLic(REFCLSID clsid, LPUNKNOWN pUnkOuter,
  297.     DWORD dwClsCtx, REFIID iid, LPVOID* ppv, BSTR bstrLicKey)
  298. {
  299.     HRESULT hr;
  300.  
  301.     if (bstrLicKey == NULL)
  302.     {
  303.         LPCLASSFACTORY pClassFactory = NULL;
  304.  
  305.         if (SUCCEEDED(hr = CoGetClassObject(clsid, dwClsCtx, NULL,
  306.             IID_IClassFactory, (void**)&pClassFactory)))
  307.         {
  308.             ASSERT(pClassFactory != NULL);
  309.             hr = pClassFactory->CreateInstance(pUnkOuter, iid, ppv);
  310.             pClassFactory->Release();
  311.         }
  312.     }
  313.     else
  314.     {
  315.         LPCLASSFACTORY2 pClassFactory = NULL;
  316.  
  317.         if (SUCCEEDED(hr = CoGetClassObject(clsid, dwClsCtx, NULL,
  318.             IID_IClassFactory2, (void**)&pClassFactory)))
  319.         {
  320.             ASSERT(pClassFactory != NULL);
  321.             hr = pClassFactory->CreateInstanceLic(pUnkOuter, NULL, iid,
  322.                 bstrLicKey, ppv);
  323.             pClassFactory->Release();
  324.         }
  325.     }
  326.  
  327.     return hr;
  328. }
  329.  
  330. AFX_STATIC_DATA const struct { DISPID dwDispID; DWORD dwFlag; } _afxAmbients[] =
  331. {
  332.     { DISPID_AMBIENT_USERMODE,          QACONTAINER_USERMODE },
  333.     { DISPID_AMBIENT_UIDEAD,            QACONTAINER_UIDEAD },
  334.     { DISPID_AMBIENT_SHOWGRABHANDLES,   QACONTAINER_SHOWGRABHANDLES },
  335.     { DISPID_AMBIENT_SHOWHATCHING,      QACONTAINER_SHOWHATCHING },
  336.     { DISPID_AMBIENT_DISPLAYASDEFAULT,  QACONTAINER_DISPLAYASDEFAULT },
  337.     { DISPID_AMBIENT_AUTOCLIP,          QACONTAINER_AUTOCLIP },
  338.     { DISPID_AMBIENT_MESSAGEREFLECT,    QACONTAINER_MESSAGEREFLECT },
  339.     { DISPID_AMBIENT_SUPPORTSMNEMONICS, QACONTAINER_SUPPORTSMNEMONICS },
  340. };
  341.  
  342. BOOL COleControlSite::QuickActivate()
  343. {
  344.     BOOL bQuickActivated = FALSE;
  345.     IQuickActivate* pQuick = NULL;
  346.     if (SUCCEEDED(m_pObject->QueryInterface(IID_IQuickActivate,
  347.         reinterpret_cast<void**>(&pQuick))))
  348.     {
  349.         ASSERT(pQuick != NULL);
  350.  
  351.         // Initialize QACONTAINER structure.
  352.         QACONTAINER qaContainer;
  353.         qaContainer.cbSize = sizeof(QACONTAINER);
  354.         qaContainer.pClientSite = &m_xOleClientSite;
  355.         qaContainer.pAdviseSink = NULL;
  356.         qaContainer.pPropertyNotifySink = &m_xPropertyNotifySink;
  357.         qaContainer.pUnkEventSink = &m_xEventSink;
  358.         qaContainer.pUndoMgr = NULL;
  359.         qaContainer.hpal = NULL;
  360.         qaContainer.pBindHost = NULL;
  361.  
  362.         // Fill ambient property values in QACONTAINER.
  363.         COleVariant var;
  364.         CWnd* pWndContain = m_pCtrlCont->m_pWnd;
  365.  
  366.         qaContainer.dwAmbientFlags = 0;
  367.         for (int i = 0; i < _countof(_afxAmbients); i++)
  368.         {
  369.             pWndContain->OnAmbientProperty(this, _afxAmbients[i].dwDispID, &var);
  370.             if (V_BOOL(&var))
  371.                 qaContainer.dwAmbientFlags |= _afxAmbients[i].dwFlag;
  372.         }
  373.  
  374.         pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_FORECOLOR, &var);
  375.         qaContainer.colorFore = V_I4(&var);
  376.         pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_BACKCOLOR, &var);
  377.         qaContainer.colorBack = V_I4(&var);
  378.         pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_APPEARANCE, &var);
  379.         qaContainer.dwAppearance = V_I2(&var);
  380.         pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_LOCALEID, &var);
  381.         qaContainer.lcid = V_I4(&var);
  382.         pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_FONT, &var);
  383.         if (FAILED(V_DISPATCH(&var)->QueryInterface(IID_IFont,
  384.             reinterpret_cast<void**>(&qaContainer.pFont))))
  385.         {
  386.             qaContainer.pFont = NULL;
  387.         }
  388.  
  389.         // Initialize QACONTROL structure.
  390.         QACONTROL qaControl;
  391.         qaControl.cbSize = sizeof(QACONTROL);
  392.  
  393.         // Do the quick activation.
  394.         if (SUCCEEDED(pQuick->QuickActivate(&qaContainer, &qaControl)))
  395.         {
  396.             // Extract return values from QACONTROL structure.
  397.             m_dwMiscStatus = qaControl.dwMiscStatus;
  398.             m_dwEventSink = qaControl.dwEventCookie;
  399.             m_dwPropNotifySink = qaControl.dwPropNotifyCookie;
  400.             bQuickActivated = TRUE;
  401.         }
  402.         pQuick->Release();
  403.  
  404.         if (qaContainer.pFont != NULL)
  405.             qaContainer.pFont->Release();
  406.     }
  407.  
  408.     return bQuickActivated;
  409. }
  410.  
  411. HRESULT COleControlSite::CreateOrLoad(REFCLSID clsid, CFile* pFile,
  412.     BOOL bStorage, BSTR bstrLicKey)
  413. {
  414.     ASSERT(m_pObject == NULL);
  415.  
  416. #ifdef _DEBUG
  417.     OLECHAR wszClsid[40];
  418.     StringFromGUID2(clsid, wszClsid, 40);
  419. #endif //_DEBUG
  420.  
  421.     HRESULT hr;
  422.     if (FAILED(hr = _AfxCoCreateInstanceLic(clsid, NULL,
  423.         CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IOleObject,
  424.         (void**)&m_pObject, bstrLicKey)))
  425.     {
  426.         TRACE1("CoCreateInstance of OLE control %ls failed.\n", wszClsid);
  427.         TRACE1(">>> Result code: 0x%08lx\n", hr);
  428.         TRACE0(">>> Is the control is properly registered?\n");
  429.         return hr;
  430.     }
  431.  
  432.     LPPERSISTSTREAMINIT pPersStm = NULL;
  433.     LPPERSISTSTORAGE pPersStg = NULL;
  434.     LPPERSISTMEMORY pPersMem = NULL;
  435.  
  436.     GetEventIID(&m_iidEvents);
  437.     // Try to quick-activate first
  438.     BOOL bQuickActivated = QuickActivate();
  439.  
  440.     if (!bQuickActivated)
  441.     {
  442.         m_pObject->GetMiscStatus(DVASPECT_CONTENT, &m_dwMiscStatus);
  443.  
  444.         // set client site first, if appropriate
  445.         if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
  446.         {
  447.             if (FAILED(hr = m_pObject->SetClientSite(&m_xOleClientSite)))
  448.             {
  449.                 TRACE1("SetClientSite on OLE control %ls failed.\n", wszClsid);
  450.                 TRACE1(">>> Result code: 0x%08lx\n", hr);
  451.                 goto CreateOrLoadFailed;
  452.             }
  453.         }
  454.     }
  455.  
  456.     ASSERT(!bStorage || pFile != NULL);
  457.  
  458.     // initialize via IPersistMemory (direct buffering)
  459.     if (pFile != NULL && !bStorage &&
  460.         SUCCEEDED(m_pObject->QueryInterface(IID_IPersistMemory, (void**)&pPersMem)) &&
  461.         pFile->GetBufferPtr(CFile::bufferCheck) != 0)
  462.     {
  463.         ASSERT(pPersMem != NULL);
  464.  
  465.         // file supports direct buffering, get its buffer pointer and size
  466.         LPVOID pvBuffer = NULL;
  467.         LPVOID pvEnd;
  468.         ULONG cbBuffer = pFile->GetBufferPtr(
  469.             CFile::bufferRead, (UINT)-1, &pvBuffer, &pvEnd);
  470.         ASSERT(((LPBYTE)pvEnd - (LPBYTE)pvBuffer) == (int)cbBuffer);
  471.  
  472.         // and then load it directly
  473.         hr = pPersMem->Load(pvBuffer, cbBuffer);
  474.         pPersMem->Release();
  475.         pPersMem = NULL;
  476.         if (FAILED(hr))
  477.             goto CreateOrLoadFailed;
  478.     }
  479.     // initialize via IPersistStreamInit
  480.     else if (!bStorage && SUCCEEDED(m_pObject->QueryInterface(
  481.         IID_IPersistStreamInit, (void**)&pPersStm)))
  482.     {
  483.         ASSERT(pPersStm != NULL);
  484.  
  485.         if (pFile == NULL)
  486.         {
  487.             // just call InitNew
  488.             hr = pPersStm->InitNew();
  489.         }
  490.         else
  491.         {
  492.             // open an IStream on the data and pass it to Load
  493.             CArchive ar(pFile, CArchive::load);
  494.             CArchiveStream stm(&ar);
  495.             hr = pPersStm->Load(&stm);
  496.         }
  497.         pPersStm->Release();
  498.  
  499.         if (FAILED(hr))
  500.         {
  501.             TRACE1("InitNew or Load on OLE control %ls failed.\n", wszClsid);
  502.             TRACE1(">>> Result code: 0x%08lx\n", hr);
  503.             goto CreateOrLoadFailed;
  504.         }
  505.     }
  506.     // initialize via IPersistStorage
  507.     else if (SUCCEEDED(m_pObject->QueryInterface(
  508.         IID_IPersistStorage, (void**)&pPersStg)))
  509.     {
  510.         ASSERT(pPersStg != NULL);
  511.  
  512.         if (pFile == NULL)
  513.         {
  514.             // create a scratch IStorage and pass it to InitNew
  515.             LPLOCKBYTES pLockBytes = NULL;
  516.             if (SUCCEEDED(hr = CreateILockBytesOnHGlobal(NULL, TRUE,
  517.                 &pLockBytes)))
  518.             {
  519.                 ASSERT(pLockBytes != NULL);
  520.                 LPSTORAGE pStorage = NULL;
  521.                 if (SUCCEEDED(hr = StgCreateDocfileOnILockBytes(pLockBytes,
  522.                     STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0,
  523.                     &pStorage)))
  524.                 {
  525.                     ASSERT(pStorage != NULL);
  526.                     hr = pPersStg->InitNew(pStorage);
  527.                     pStorage->Release();
  528.                 }
  529.                 pLockBytes->Release();
  530.             }
  531.         }
  532.         else if (bStorage)
  533.         {
  534.             // copy data to an HGLOBAL, so we can build an IStorage on it
  535.             UINT cb = pFile->GetLength();
  536.             HGLOBAL hGlobal;
  537.             BYTE* pbData;
  538.  
  539.             if (((hGlobal = GlobalAlloc(GMEM_FIXED, cb)) != NULL) &&
  540.                 ((pbData = (BYTE*)GlobalLock(hGlobal)) != NULL))
  541.             {
  542.                 pFile->Read(pbData, cb);
  543.                 GlobalUnlock(hGlobal);
  544.             }
  545.             else
  546.             {
  547.                 hr = E_OUTOFMEMORY;
  548.                 hGlobal = NULL;
  549.             }
  550.  
  551.             // open an IStorage on the data and pass it to Load
  552.             LPLOCKBYTES pLockBytes = NULL;
  553.             if ((hGlobal != NULL) &&
  554.                 SUCCEEDED(hr = CreateILockBytesOnHGlobal(hGlobal, TRUE,
  555.                 &pLockBytes)))
  556.             {
  557.                 ASSERT(pLockBytes != NULL);
  558.                 LPSTORAGE pStorage = NULL;
  559.                 if (SUCCEEDED(hr = StgOpenStorageOnILockBytes(pLockBytes, NULL,
  560.                     STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &pStorage)))
  561.                 {
  562.                     ASSERT(pStorage != NULL);
  563.                     hr = pPersStg->Load(pStorage);
  564.                     pStorage->Release();
  565.                 }
  566.                 pLockBytes->Release();
  567.             }
  568.         }
  569.         else
  570.         {
  571.             hr = E_UNEXPECTED;
  572.         }
  573.         pPersStg->Release();
  574.  
  575.         if (FAILED(hr))
  576.         {
  577.             TRACE1("InitNew or Load on OLE control %ls failed.\n", wszClsid);
  578.             TRACE1(">>> Result code: 0x%08lx\n", hr);
  579.             goto CreateOrLoadFailed;
  580.         }
  581.     }
  582.     else
  583.     {
  584.         TRACE1("Persistence not supported on OLE control %ls.\n", wszClsid);
  585.         TRACE1(">>> Result code: 0x%08lx\n", hr);
  586.         goto CreateOrLoadFailed;
  587.     }
  588.  
  589.     if (!bQuickActivated)
  590.     {
  591.         // set client site last, if appropriate
  592.         if (!(m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
  593.         {
  594.             if (FAILED(hr = m_pObject->SetClientSite(&m_xOleClientSite)))
  595.             {
  596.                 TRACE1("SetClientSite on OLE control %ls failed.\n", wszClsid);
  597.                 TRACE1(">>> Result code: 0x%08lx\n", hr);
  598.                 goto CreateOrLoadFailed;
  599.             }
  600.         }
  601.     }
  602.  
  603. CreateOrLoadFailed:
  604.     if (FAILED(hr) && (m_pObject != NULL))
  605.     {
  606.         m_pObject->Close(OLECLOSE_NOSAVE);
  607.         m_pObject->Release();
  608.         m_pObject = NULL;
  609.     }
  610.  
  611.     if (pPersMem != NULL)
  612.         pPersMem->Release();
  613.  
  614.     if (bQuickActivated && SUCCEEDED(hr))
  615.         hr = S_QUICKACTIVATED;
  616.  
  617.     return hr;
  618. }
  619.  
  620. UINT COleControlSite::GetID()
  621. {
  622.     return m_nID;
  623. }
  624.  
  625. HRESULT COleControlSite::DoVerb(LONG nVerb, LPMSG lpMsg)
  626. {
  627.     return m_pObject->DoVerb(nVerb, lpMsg, &m_xOleClientSite, 0,
  628.         m_pCtrlCont->m_pWnd->m_hWnd, m_rect);
  629. }
  630.  
  631. BOOL COleControlSite::IsDefaultButton()
  632. {
  633.     return ((m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON) &&
  634.         (m_dwStyle & BS_DEFPUSHBUTTON));
  635. }
  636.  
  637. DWORD COleControlSite::GetDefBtnCode()
  638. {
  639.     if (m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON)
  640.         return (m_dwStyle & BS_DEFPUSHBUTTON) ?
  641.             DLGC_DEFPUSHBUTTON :
  642.             DLGC_UNDEFPUSHBUTTON;
  643.     else
  644.         return 0;
  645. }
  646.  
  647. void COleControlSite::SetDefaultButton(BOOL bDefault)
  648. {
  649.     if (!(m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON))
  650.         return;
  651.  
  652.     if (((m_dwStyle & BS_DEFPUSHBUTTON) != 0) == bDefault)
  653.         return;
  654.  
  655.     m_dwStyle ^= BS_DEFPUSHBUTTON;
  656.  
  657.     // Notify control that its "defaultness" has changed.
  658.     LPOLECONTROL pOleCtl = NULL;
  659.     if (SUCCEEDED(m_pObject->QueryInterface(IID_IOleControl,
  660.         (LPVOID*)&pOleCtl)))
  661.     {
  662.         ASSERT(pOleCtl != NULL);
  663.         pOleCtl->OnAmbientPropertyChange(DISPID_AMBIENT_DISPLAYASDEFAULT);
  664.         pOleCtl->Release();
  665.     }
  666. }
  667.  
  668. DWORD COleControlSite::ConnectSink(REFIID iid, LPUNKNOWN punkSink)
  669. {
  670.     ASSERT(m_pObject != NULL);
  671.  
  672.     LPCONNECTIONPOINTCONTAINER pConnPtCont;
  673.  
  674.     if ((m_pObject != NULL) &&
  675.         SUCCEEDED(m_pObject->QueryInterface(IID_IConnectionPointContainer,
  676.             (LPVOID*)&pConnPtCont)))
  677.     {
  678.         ASSERT(pConnPtCont != NULL);
  679.         LPCONNECTIONPOINT pConnPt = NULL;
  680.         DWORD dwCookie = 0;
  681.  
  682.         if (SUCCEEDED(pConnPtCont->FindConnectionPoint(iid, &pConnPt)))
  683.         {
  684.             ASSERT(pConnPt != NULL);
  685.             pConnPt->Advise(punkSink, &dwCookie);
  686.             pConnPt->Release();
  687.         }
  688.  
  689.         pConnPtCont->Release();
  690.         return dwCookie;
  691.     }
  692.  
  693.     return 0;
  694. }
  695.  
  696. void COleControlSite::DisconnectSink(REFIID iid, DWORD dwCookie)
  697. {
  698.     if (dwCookie == 0 || m_pObject == NULL)
  699.         return;
  700.  
  701.     LPCONNECTIONPOINTCONTAINER pConnPtCont;
  702.  
  703.     if (SUCCEEDED(m_pObject->QueryInterface(IID_IConnectionPointContainer,
  704.             (LPVOID*)&pConnPtCont)))
  705.     {
  706.         ASSERT(pConnPtCont != NULL);
  707.         LPCONNECTIONPOINT pConnPt = NULL;
  708.  
  709.         if (SUCCEEDED(pConnPtCont->FindConnectionPoint(iid, &pConnPt)))
  710.         {
  711.             ASSERT(pConnPt != NULL);
  712.             pConnPt->Unadvise(dwCookie);
  713.             pConnPt->Release();
  714.         }
  715.  
  716.         pConnPtCont->Release();
  717.     }
  718. }
  719.  
  720. #define IMPLTYPE_MASK \
  721.     (IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE | IMPLTYPEFLAG_FRESTRICTED)
  722.  
  723. #define IMPLTYPE_DEFAULTSOURCE \
  724.     (IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE)
  725.  
  726. BOOL COleControlSite::GetEventIID(IID* piid)
  727. {
  728.     *piid = GUID_NULL;
  729.  
  730.     ASSERT(m_pObject != NULL);
  731.  
  732.     // Use IProvideClassInfo2, if control supports it.
  733.     LPPROVIDECLASSINFO2 pPCI2 = NULL;
  734.  
  735.     if (SUCCEEDED(m_pObject->QueryInterface(IID_IProvideClassInfo2,
  736.         (LPVOID*)&pPCI2)))
  737.     {
  738.         ASSERT(pPCI2 != NULL);
  739.  
  740.         if (SUCCEEDED(pPCI2->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID, piid)))
  741.             ASSERT(!IsEqualIID(*piid, GUID_NULL));
  742.         else
  743.             ASSERT(IsEqualIID(*piid, GUID_NULL));
  744.  
  745.         pPCI2->Release();
  746.     }
  747.  
  748.     // Fall back on IProvideClassInfo, if IProvideClassInfo2 not supported.
  749.     LPPROVIDECLASSINFO pPCI = NULL;
  750.  
  751.     if (IsEqualIID(*piid, GUID_NULL) &&
  752.         SUCCEEDED(m_pObject->QueryInterface(IID_IProvideClassInfo,
  753.         (LPVOID*)&pPCI)))
  754.     {
  755.         ASSERT(pPCI != NULL);
  756.  
  757.         LPTYPEINFO pClassInfo = NULL;
  758.  
  759.         if (SUCCEEDED(pPCI->GetClassInfo(&pClassInfo)))
  760.         {
  761.             ASSERT(pClassInfo != NULL);
  762.  
  763.             LPTYPEATTR pClassAttr;
  764.             if (SUCCEEDED(pClassInfo->GetTypeAttr(&pClassAttr)))
  765.             {
  766.                 ASSERT(pClassAttr != NULL);
  767.                 ASSERT(pClassAttr->typekind == TKIND_COCLASS);
  768.  
  769.                 // Search for typeinfo of the default events interface.
  770.  
  771.                 int nFlags;
  772.                 HREFTYPE hRefType;
  773.  
  774.                 for (unsigned int i = 0; i < pClassAttr->cImplTypes; i++)
  775.                 {
  776.                     if (SUCCEEDED(pClassInfo->GetImplTypeFlags(i, &nFlags)) &&
  777.                         ((nFlags & IMPLTYPE_MASK) == IMPLTYPE_DEFAULTSOURCE))
  778.                     {
  779.                         // Found it.  Now look at its attributes to get IID.
  780.  
  781.                         LPTYPEINFO pEventInfo = NULL;
  782.  
  783.                         if (SUCCEEDED(pClassInfo->GetRefTypeOfImplType(i,
  784.                                 &hRefType)) &&
  785.                             SUCCEEDED(pClassInfo->GetRefTypeInfo(hRefType,
  786.                                 &pEventInfo)))
  787.                         {
  788.                             ASSERT(pEventInfo != NULL);
  789.  
  790.                             LPTYPEATTR pEventAttr;
  791.  
  792.                             if (SUCCEEDED(pEventInfo->GetTypeAttr(&pEventAttr)))
  793.                             {
  794.                                 ASSERT(pEventAttr != NULL);
  795.                                 *piid = pEventAttr->guid;
  796.                                 pEventInfo->ReleaseTypeAttr(pEventAttr);
  797.                             }
  798.  
  799.                             pEventInfo->Release();
  800.                         }
  801.  
  802.                         break;
  803.                     }
  804.                 }
  805.  
  806.                 pClassInfo->ReleaseTypeAttr(pClassAttr);
  807.             }
  808.  
  809.             pClassInfo->Release();
  810.         }
  811.  
  812.         pPCI->Release();
  813.     }
  814.  
  815.     return (!IsEqualIID(*piid, GUID_NULL));
  816. }
  817.  
  818. void COleControlSite::GetControlInfo()
  819. {
  820.     memset(&m_ctlInfo, 0, sizeof(CONTROLINFO));
  821.     m_ctlInfo.cb = sizeof(CONTROLINFO);
  822.     LPOLECONTROL pOleCtl = NULL;
  823.  
  824.     if (SUCCEEDED(m_pObject->QueryInterface(IID_IOleControl,
  825.         (LPVOID*)&pOleCtl)))
  826.     {
  827.         ASSERT(pOleCtl != NULL);
  828.         pOleCtl->GetControlInfo(&m_ctlInfo);
  829.         pOleCtl->Release();
  830.     }
  831. }
  832.  
  833. BOOL COleControlSite::IsMatchingMnemonic(LPMSG lpMsg)
  834. {
  835. //  return IsAccelerator(m_ctlInfo.hAccel, m_ctlInfo.cAccel, lpMsg, NULL);
  836.  
  837.     if ((m_ctlInfo.cAccel == 0) || (m_ctlInfo.hAccel == NULL))
  838.         return FALSE;
  839.  
  840.     ACCEL* pAccel = new ACCEL[m_ctlInfo.cAccel];
  841.     int cAccel = CopyAcceleratorTable(m_ctlInfo.hAccel, pAccel, m_ctlInfo.cAccel);
  842.     ASSERT(cAccel == m_ctlInfo.cAccel);
  843.  
  844.     BOOL bMatch = FALSE;
  845.     for (int i = 0; i < cAccel; i++)
  846.     {
  847.         BOOL fVirt = (lpMsg->message == WM_SYSCHAR ? FALT : 0);
  848.         WORD key = LOWORD(lpMsg->wParam);
  849.         if (((pAccel[i].fVirt & ~FNOINVERT) == fVirt) &&
  850.             (pAccel[i].key == key))
  851.         {
  852.             bMatch = TRUE;
  853.             break;
  854.         }
  855.     }
  856.  
  857.     delete [] pAccel;
  858.     return bMatch;
  859. }
  860.  
  861. void COleControlSite::SendMnemonic(LPMSG lpMsg)
  862. {
  863.     if (!(m_dwMiscStatus & OLEMISC_NOUIACTIVATE))
  864.         SetFocus();
  865.  
  866.     LPOLECONTROL pOleCtl = NULL;
  867.  
  868.     if (SUCCEEDED(m_pObject->QueryInterface(IID_IOleControl,
  869.         (LPVOID*)&pOleCtl)))
  870.     {
  871.         ASSERT(pOleCtl != NULL);
  872.         pOleCtl->OnMnemonic(lpMsg);
  873.         pOleCtl->Release();
  874.     }
  875. }
  876.  
  877. void COleControlSite::FreezeEvents(BOOL bFreeze)
  878. {
  879.     LPOLECONTROL pOleCtl = NULL;
  880.     if (SUCCEEDED(m_pObject->QueryInterface(IID_IOleControl,
  881.         (LPVOID*)&pOleCtl)))
  882.     {
  883.         ASSERT(pOleCtl != NULL);
  884.         pOleCtl->FreezeEvents(bFreeze);
  885.         pOleCtl->Release();
  886.     }
  887. }
  888.  
  889. void COleControlSite::AttachWindow()
  890. {
  891.     HWND hWnd = NULL;
  892.     if (SUCCEEDED(m_pInPlaceObject->GetWindow(&hWnd)))
  893.     {
  894.         ASSERT(hWnd != NULL);
  895.         if (m_hWnd != hWnd)
  896.         {
  897.             m_hWnd = hWnd;
  898.  
  899.             if (m_pWndCtrl != NULL)
  900.             {
  901.                 ASSERT(m_pWndCtrl->m_hWnd == NULL); // Window already attached?
  902.                 m_pWndCtrl->Attach(m_hWnd);
  903.  
  904.                 ASSERT(m_pWndCtrl->m_pCtrlSite == NULL ||
  905.                     m_pWndCtrl->m_pCtrlSite == this);
  906.                 m_pWndCtrl->m_pCtrlSite = this;
  907.             }
  908.         }
  909.     }
  910. }
  911.  
  912. void COleControlSite::DetachWindow()
  913. {
  914.     m_hWnd = NULL;
  915.  
  916.     if (m_pWndCtrl != NULL)
  917.     {
  918.         if (m_pWndCtrl->m_hWnd != NULL)
  919.         {
  920.             WNDPROC* lplpfn = m_pWndCtrl->GetSuperWndProcAddr();
  921.             ASSERT(lplpfn != NULL);
  922.             if (::IsWindow(m_pWndCtrl->m_hWnd) && *lplpfn != NULL)
  923.                 m_pWndCtrl->UnsubclassWindow();
  924.  
  925.             m_pWndCtrl->Detach();
  926.         }
  927.  
  928.         m_pWndCtrl->m_pCtrlSite = NULL;
  929.     }
  930. }
  931.  
  932. BOOL COleControlSite::OnEvent(AFX_EVENT* pEvent)
  933. {
  934.     // If this control has a proxy CWnd, look for a matching ON_*_REFLECT
  935.     // entry for this event in its event map.
  936.     if ((m_pWndCtrl != NULL) &&
  937.         m_pWndCtrl->OnCmdMsg(m_nID, CN_EVENT, pEvent, NULL))
  938.     {
  939.         return TRUE;
  940.     }
  941.  
  942.     // Proxy CWnd isn't interested, so pass the event along to the container.
  943.     return m_pCtrlCont->m_pWnd->OnCmdMsg(m_nID, CN_EVENT, pEvent, NULL);
  944. }
  945.  
  946. /////////////////////////////////////////////////////////////////////////////
  947. // invoke helpers
  948.  
  949. void COleControlSite::InvokeHelperV(DISPID dwDispID, WORD wFlags,
  950.     VARTYPE vtRet, void* pvRet, const BYTE* pbParamInfo, va_list argList)
  951. {
  952.     if (m_dispDriver.m_lpDispatch == NULL)
  953.     {
  954.         // no dispatch pointer yet; find it now
  955.         LPDISPATCH pDispatch;
  956.  
  957.         if ((m_pObject != NULL) &&
  958.             SUCCEEDED(m_pObject->QueryInterface(IID_IDispatch,
  959.                 (LPVOID*)&pDispatch)))
  960.         {
  961.             ASSERT(pDispatch != NULL);
  962.             m_dispDriver.AttachDispatch(pDispatch);
  963.         }
  964.     }
  965.  
  966.     if (m_dispDriver.m_lpDispatch == NULL)
  967.     {
  968.         // couldn't find dispatch pointer
  969.         TRACE0("Warning: control has no IDispatch interface.");
  970.         return;
  971.     }
  972.  
  973.     // delegate call to m_dispDriver
  974.     m_dispDriver.InvokeHelperV(dwDispID, wFlags, vtRet, pvRet, pbParamInfo,
  975.         argList);
  976. }
  977.  
  978. void COleControlSite::SetPropertyV(DISPID dwDispID, VARTYPE vtProp, va_list argList)
  979. {
  980.     BYTE rgbParams[2];
  981.     if (vtProp & VT_BYREF)
  982.     {
  983.         vtProp &= ~VT_BYREF;
  984.         vtProp |= VT_MFCBYREF;
  985.     }
  986.  
  987. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  988.     if (vtProp == VT_BSTR)
  989.         vtProp = VT_BSTRA;
  990. #endif
  991.  
  992.     WORD wFlags;
  993.     if (vtProp & VT_MFCFORCEPUTREF)
  994.     {
  995.         wFlags = DISPATCH_PROPERTYPUTREF;
  996.         vtProp &= ~VT_MFCFORCEPUTREF;
  997.     }
  998.     else
  999.     {
  1000.         if (vtProp == VT_DISPATCH)
  1001.             wFlags = DISPATCH_PROPERTYPUTREF;
  1002.         else
  1003.             wFlags = DISPATCH_PROPERTYPUT;
  1004.     }
  1005.  
  1006.     rgbParams[0] = (BYTE)vtProp;
  1007.     rgbParams[1] = 0;
  1008.     InvokeHelperV(dwDispID, wFlags, VT_EMPTY, NULL, rgbParams, argList);
  1009. }
  1010.  
  1011. void AFX_CDECL COleControlSite::InvokeHelper(DISPID dwDispID, WORD wFlags, VARTYPE vtRet,
  1012.     void* pvRet, const BYTE* pbParamInfo, ...)
  1013. {
  1014.     va_list argList;
  1015.     va_start(argList, pbParamInfo);
  1016.     InvokeHelperV(dwDispID, wFlags, vtRet, pvRet, pbParamInfo, argList);
  1017.     va_end(argList);
  1018. }
  1019.  
  1020. void COleControlSite::GetProperty(DISPID dwDispID, VARTYPE vtProp,
  1021.     void* pvProp) const
  1022. {
  1023.     const_cast<COleControlSite*>(this)->InvokeHelper(dwDispID,
  1024.         DISPATCH_PROPERTYGET, vtProp, pvProp, NULL);
  1025. }
  1026.  
  1027. void AFX_CDECL COleControlSite::SetProperty(DISPID dwDispID, VARTYPE vtProp, ...)
  1028. {
  1029.     va_list argList;    // really only one arg, but...
  1030.     va_start(argList, vtProp);
  1031.     SetPropertyV(dwDispID, vtProp, argList);
  1032.     va_end(argList);
  1033. }
  1034.  
  1035. BOOL AFX_CDECL COleControlSite::SafeSetProperty(DISPID dwDispID, VARTYPE vtProp, ...)
  1036. {
  1037.     va_list argList;    // really only one arg, but...
  1038.     va_start(argList, vtProp);
  1039.  
  1040.     BOOL bSuccess;
  1041.  
  1042.     TRY
  1043.     {
  1044.         SetPropertyV(dwDispID, vtProp, argList);
  1045.         bSuccess = TRUE;
  1046.     }
  1047.     CATCH_ALL(e)
  1048.     {
  1049.         DELETE_EXCEPTION(e);
  1050.         bSuccess = FALSE;
  1051.     }
  1052.     END_CATCH_ALL
  1053.  
  1054.     va_end(argList);
  1055.     return bSuccess;
  1056. }
  1057.  
  1058. /////////////////////////////////////////////////////////////////////////////
  1059. // special cases for CWnd functions
  1060.  
  1061. DWORD COleControlSite::GetStyle() const
  1062. {
  1063.     DWORD dwStyle = m_dwStyle |
  1064.         (::GetWindowLong(m_hWnd, GWL_STYLE) & WS_VISIBLE);
  1065.  
  1066.     TRY
  1067.     {
  1068.         BOOL bEnabled = TRUE;
  1069.         GetProperty(DISPID_ENABLED, VT_BOOL, &bEnabled);
  1070.         if (!bEnabled)
  1071.             dwStyle |= WS_DISABLED;
  1072.     }
  1073.     END_TRY
  1074.  
  1075.     TRY
  1076.     {
  1077.         short sBorderStyle = 0;
  1078.         GetProperty(DISPID_BORDERSTYLE, VT_I2, &sBorderStyle);
  1079.         if (sBorderStyle == 1)
  1080.             dwStyle |= WS_BORDER;
  1081.     }
  1082.     END_TRY
  1083.  
  1084.     return dwStyle;
  1085. }
  1086.  
  1087. DWORD COleControlSite::GetExStyle() const
  1088. {
  1089.     DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);
  1090.  
  1091.     TRY
  1092.     {
  1093.         short sAppearance = 0;
  1094.         GetProperty(DISPID_APPEARANCE, VT_I2, &sAppearance);
  1095.         if (sAppearance == 1)
  1096.             dwExStyle |= WS_EX_CLIENTEDGE;
  1097.     }
  1098.     END_TRY
  1099.  
  1100.     return dwExStyle;
  1101. }
  1102.  
  1103. BOOL COleControlSite::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
  1104. {
  1105.     m_dwStyle = ((m_dwStyle & ~dwRemove) | dwAdd) & m_dwStyleMask;
  1106.  
  1107.     // Enabled property
  1108.     if ((dwRemove & WS_DISABLED) || (dwAdd & WS_DISABLED))
  1109.     {
  1110.         if (SafeSetProperty(DISPID_ENABLED, VT_BOOL, (~dwAdd & WS_DISABLED)))
  1111.         {
  1112.             dwRemove &= ~WS_DISABLED;
  1113.             dwAdd &= ~WS_DISABLED;
  1114.         }
  1115.     }
  1116.  
  1117.     // BorderStyle property
  1118.     if ((dwRemove & WS_BORDER) || (dwAdd & WS_BORDER))
  1119.     {
  1120.         if (SafeSetProperty(DISPID_BORDERSTYLE, VT_I2, (dwAdd & WS_BORDER)))
  1121.         {
  1122.             dwRemove &= ~WS_BORDER;
  1123.             dwAdd &= ~WS_BORDER;
  1124.         }
  1125.     }
  1126.  
  1127.     return CWnd::ModifyStyle(m_hWnd, dwRemove, dwAdd, nFlags);
  1128. }
  1129.  
  1130. BOOL COleControlSite::ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
  1131. {
  1132.     // BorderStyle property
  1133.     if ((dwRemove & WS_EX_CLIENTEDGE) || (dwAdd & WS_EX_CLIENTEDGE))
  1134.     {
  1135.         if (SafeSetProperty(DISPID_APPEARANCE, VT_I2, (dwAdd & WS_EX_CLIENTEDGE)))
  1136.         {
  1137.             dwRemove &= ~WS_EX_CLIENTEDGE;
  1138.             dwAdd &= ~WS_EX_CLIENTEDGE;
  1139.         }
  1140.     }
  1141.  
  1142.     return CWnd::ModifyStyleEx(m_hWnd, dwRemove, dwAdd, nFlags);
  1143. }
  1144.  
  1145. void COleControlSite::SetWindowText(LPCTSTR lpszString)
  1146. {
  1147.     ASSERT(::IsWindow(m_hWnd));
  1148.  
  1149.     if (!SafeSetProperty(DISPID_CAPTION, VT_BSTR, lpszString))
  1150.         SafeSetProperty(DISPID_TEXT, VT_BSTR, lpszString);
  1151. }
  1152.  
  1153. void COleControlSite::GetWindowText(CString& str) const
  1154. {
  1155.     ASSERT(::IsWindow(m_hWnd));
  1156.  
  1157.     TRY
  1158.     {
  1159.         GetProperty(DISPID_CAPTION, VT_BSTR, &str);
  1160.     }
  1161.     CATCH_ALL(e)
  1162.     {
  1163.         DELETE_EXCEPTION(e);
  1164.  
  1165.         TRY
  1166.         {
  1167.             GetProperty(DISPID_TEXT, VT_BSTR, &str);
  1168.         }
  1169.         END_TRY
  1170.     }
  1171.     END_CATCH_ALL
  1172. }
  1173.  
  1174. int COleControlSite::GetWindowText(LPTSTR lpszString, int nMaxCount) const
  1175. {
  1176.     ASSERT(nMaxCount > 0);
  1177.     CString str;
  1178.     GetWindowText(str);
  1179.     lstrcpyn(lpszString, str, nMaxCount);
  1180.     return lstrlen(lpszString);
  1181. }
  1182.  
  1183. int COleControlSite::GetWindowTextLength() const
  1184. {
  1185.     CString str;
  1186.     GetWindowText(str);
  1187.     return str.GetLength();
  1188. }
  1189.  
  1190. int COleControlSite::GetDlgCtrlID() const
  1191. {
  1192.     return (int)m_nID;
  1193. }
  1194.  
  1195. int COleControlSite::SetDlgCtrlID(int nID)
  1196. {
  1197.     int nPrevID = (int)m_nID;
  1198.     m_nID = (UINT)nID;
  1199.     return nPrevID;
  1200. }
  1201.  
  1202. void COleControlSite::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL)
  1203. {
  1204.     ASSERT(m_pInPlaceObject != NULL);
  1205.     ASSERT(m_pObject != NULL);
  1206.  
  1207.     CRect rectOld(m_rect);
  1208.     m_rect.SetRect(x, y, x + nWidth, y + nHeight);
  1209.     if (SetExtent())
  1210.     {
  1211.         m_rect.SetRect(x, y, x + m_rect.Width(), y + m_rect.Height());
  1212.         m_pInPlaceObject->SetObjectRects(m_rect, m_rect);
  1213.     }
  1214.     else
  1215.     {
  1216.         m_rect = rectOld;
  1217.     }
  1218. }
  1219.  
  1220. BOOL COleControlSite::SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx,
  1221.     int cy, UINT nFlags)
  1222. {
  1223.     if (nFlags & SWP_HIDEWINDOW)
  1224.         ShowWindow(SW_HIDE);
  1225.  
  1226.     if ((nFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
  1227.     {
  1228.         int xNew;
  1229.         int yNew;
  1230.         if (nFlags & SWP_NOMOVE)
  1231.         {
  1232.             xNew = m_rect.left;
  1233.             yNew = m_rect.top;
  1234.         }
  1235.         else
  1236.         {
  1237.             xNew = x;
  1238.             yNew = y;
  1239.         }
  1240.  
  1241.         int cxNew;
  1242.         int cyNew;
  1243.         if (nFlags & SWP_NOSIZE)
  1244.         {
  1245.             cxNew = m_rect.Width();
  1246.             cyNew = m_rect.Height();
  1247.         }
  1248.         else
  1249.         {
  1250.             cxNew = cx;
  1251.             cyNew = cy;
  1252.         }
  1253.  
  1254.         MoveWindow(xNew, yNew, cxNew, cyNew, !(nFlags & SWP_NOREDRAW));
  1255.     }
  1256.  
  1257.     if (nFlags & SWP_SHOWWINDOW)
  1258.         ShowWindow(SW_SHOW);
  1259.  
  1260.     // we've handled hide, move, size, and show; let Windows do the rest
  1261.     nFlags &= ~(SWP_HIDEWINDOW|SWP_SHOWWINDOW);
  1262.     nFlags |= (SWP_NOMOVE|SWP_NOSIZE);
  1263.     return ::SetWindowPos(m_hWnd, pWndInsertAfter->GetSafeHwnd(),
  1264.         x, y, cx, cy, nFlags);
  1265. }
  1266.  
  1267. BOOL COleControlSite::ShowWindow(int nCmdShow)
  1268. {
  1269.     BOOL bReturn = ::IsWindowVisible(m_hWnd);
  1270.     int iVerb = 0;
  1271.     switch (nCmdShow)
  1272.     {
  1273.     case SW_SHOW:
  1274.     case SW_SHOWNORMAL:
  1275.     case SW_SHOWNOACTIVATE:
  1276.         iVerb = OLEIVERB_SHOW;
  1277.         break;
  1278.  
  1279.     case SW_HIDE:
  1280.         iVerb = OLEIVERB_HIDE;
  1281.         break;
  1282.     }
  1283.  
  1284.     if (iVerb != 0)
  1285.         DoVerb(iVerb);
  1286.  
  1287.     return bReturn;
  1288. }
  1289.  
  1290. BOOL COleControlSite::IsWindowEnabled() const
  1291. {
  1292.     BOOL bEnabled = TRUE;
  1293.     TRY
  1294.         GetProperty(DISPID_ENABLED, VT_BOOL, &bEnabled);
  1295.     END_TRY
  1296.  
  1297.     return bEnabled;
  1298. }
  1299.  
  1300. BOOL COleControlSite::EnableWindow(BOOL bEnable)
  1301. {
  1302.     BOOL bResult;
  1303.     TRY
  1304.     {
  1305.         GetProperty(DISPID_ENABLED, VT_BOOL, &bResult);
  1306.         SetProperty(DISPID_ENABLED, VT_BOOL, bEnable);
  1307.     }
  1308.     CATCH_ALL(e)
  1309.     {
  1310.         DELETE_EXCEPTION(e);
  1311.         bResult = TRUE;
  1312.     }
  1313.     END_CATCH_ALL
  1314.  
  1315.     return !bResult;    // return TRUE if previously disabled
  1316. }
  1317.  
  1318. CWnd* COleControlSite::SetFocus()
  1319. {
  1320.     if (m_dwMiscStatus & OLEMISC_NOUIACTIVATE)
  1321.         return CWnd::FromHandle(::SetFocus(m_hWnd));
  1322.  
  1323.     CWnd* pWndPrev = CWnd::GetFocus();
  1324.     DoVerb(OLEIVERB_UIACTIVATE);
  1325.     return pWndPrev;
  1326. }
  1327.  
  1328. void COleControlSite::EnableDSC()
  1329. {
  1330.     if (m_pDataSourceControl == NULL)
  1331.     {
  1332.         m_pDataSourceControl = new CDataSourceControl(this);
  1333.         m_pDataSourceControl->Initialize();
  1334.     }
  1335. }
  1336.  
  1337. void COleControlSite::BindDefaultProperty(DISPID dwDispID, VARTYPE vtProp, LPCTSTR szFieldName, CWnd* pDSCWnd)
  1338. {
  1339.     // Remove any previous binding
  1340.     if (m_pDSCSite != NULL)
  1341.     {
  1342.         m_pDSCSite->m_pDataSourceControl->BindProp(this, FALSE);
  1343.         m_pDSCSite->m_pDataSourceControl->BindColumns();
  1344.         m_pDSCSite = NULL;
  1345.     }
  1346.  
  1347.     if (pDSCWnd != NULL)
  1348.     {
  1349.         ASSERT(pDSCWnd->m_pCtrlSite);  // must be an OLE control
  1350.         pDSCWnd->m_pCtrlSite->EnableDSC();
  1351.         m_pDSCSite = pDSCWnd->m_pCtrlSite;
  1352.         m_defdispid = dwDispID;
  1353.         m_dwType = vtProp;
  1354.         m_strDataField = szFieldName;
  1355.         m_pDSCSite->m_pDataSourceControl->BindProp(this, TRUE);
  1356.         if (m_pDSCSite != NULL)
  1357.             m_pDSCSite->m_pDataSourceControl->BindColumns();
  1358.     }
  1359. }
  1360.  
  1361. void COleControlSite::BindProperty(DISPID dwDispId, CWnd* pWndDSC)
  1362. {
  1363.     ASSERT(pWndDSC == NULL || pWndDSC->m_pCtrlSite);
  1364.     if (pWndDSC != NULL && dwDispId != DISPID_UNKNOWN)
  1365.     {
  1366.         m_pBindings = new CDataBoundProperty(m_pBindings, dwDispId, 0);
  1367.         m_pBindings->m_pDSCSite = pWndDSC->m_pCtrlSite;
  1368.         m_pBindings->m_pClientSite = this;
  1369.         m_pBindings->m_pDSCSite->EnableDSC();
  1370.         m_pBindings->m_pDSCSite->m_pDataSourceControl->BindProp(m_pBindings, TRUE);
  1371.     }
  1372.     else
  1373.     {
  1374.         // Try and locate the particular property to unbind
  1375.         // if dwDispId == DISPID_UNKNOWN && pWndDSC == NULL it unbinds all properties
  1376.         // if dwDispId == DISPID_UNKNOWN && pWndDSC != NULL it unbinds properties for that DSC
  1377.         CDataBoundProperty *pCurrent = m_pBindings;
  1378.         CDataBoundProperty* pPrev = NULL;
  1379.         while (pCurrent != NULL)
  1380.         {
  1381.             CDataBoundProperty* pNext = pCurrent->GetNext();
  1382.             if (dwDispId == DISPID_UNKNOWN || pCurrent->m_dispid == dwDispId)
  1383.             {
  1384.                 if (pWndDSC == NULL || pWndDSC->m_pCtrlSite == pCurrent->m_pDSCSite)
  1385.                 {
  1386.                     if (pPrev != NULL)
  1387.                         pPrev->m_pNext = pNext;
  1388.                     else
  1389.                         m_pBindings = pNext;
  1390.                     if (pCurrent->m_pDSCSite != NULL && pCurrent->m_pDSCSite->m_pDataSourceControl != NULL)
  1391.                         pCurrent->m_pDSCSite->m_pDataSourceControl->BindProp(pCurrent, FALSE);
  1392.                     delete pCurrent;
  1393.                 }
  1394.             }
  1395.             if (pPrev != NULL)
  1396.                 pPrev = pPrev->GetNext();
  1397.             pCurrent = pNext;
  1398.         }
  1399.     }
  1400. }
  1401.  
  1402.  
  1403. /////////////////////////////////////////////////////////////////////////////
  1404. // COleControlSite::XOleClientSite
  1405.  
  1406. STDMETHODIMP_(ULONG) COleControlSite::XOleClientSite::AddRef()
  1407. {
  1408.     METHOD_PROLOGUE_EX_(COleControlSite, OleClientSite)
  1409.     return (ULONG)pThis->InternalAddRef();
  1410. }
  1411.  
  1412. STDMETHODIMP_(ULONG) COleControlSite::XOleClientSite::Release()
  1413. {
  1414.     METHOD_PROLOGUE_EX_(COleControlSite, OleClientSite)
  1415.     return (ULONG)pThis->InternalRelease();
  1416. }
  1417.  
  1418. STDMETHODIMP COleControlSite::XOleClientSite::QueryInterface(
  1419.     REFIID iid, LPVOID* ppvObj)
  1420. {
  1421.     METHOD_PROLOGUE_EX_(COleControlSite, OleClientSite)
  1422.     return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
  1423. }
  1424.  
  1425. STDMETHODIMP COleControlSite::XOleClientSite::SaveObject()
  1426. {
  1427.     return E_NOTIMPL;
  1428. }
  1429.  
  1430. STDMETHODIMP COleControlSite::XOleClientSite::GetMoniker(DWORD, DWORD,
  1431.     LPMONIKER*)
  1432. {
  1433.     return E_NOTIMPL;
  1434. }
  1435.  
  1436. STDMETHODIMP COleControlSite::XOleClientSite::GetContainer(
  1437.     LPOLECONTAINER* ppContainer)
  1438. {
  1439.     METHOD_PROLOGUE_EX_(COleControlSite, OleClientSite)
  1440.     return (HRESULT)pThis->m_pCtrlCont->InternalQueryInterface(
  1441.         &IID_IOleContainer, (LPVOID*)ppContainer);
  1442. }
  1443.  
  1444. STDMETHODIMP COleControlSite::XOleClientSite::ShowObject()
  1445. {
  1446.     METHOD_PROLOGUE_EX(COleControlSite, OleClientSite)
  1447.     pThis->AttachWindow();
  1448.     return S_OK;
  1449. }
  1450.  
  1451. STDMETHODIMP COleControlSite::XOleClientSite::OnShowWindow(BOOL)
  1452. {
  1453.     return S_OK;
  1454. }
  1455.  
  1456. STDMETHODIMP COleControlSite::XOleClientSite::RequestNewObjectLayout()
  1457. {
  1458.     return E_NOTIMPL;
  1459. }
  1460.  
  1461.  
  1462. /////////////////////////////////////////////////////////////////////////////
  1463. // COleControlSite::XOleIPSite
  1464.  
  1465. STDMETHODIMP_(ULONG) COleControlSite::XOleIPSite::AddRef()
  1466. {
  1467.     METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
  1468.     return (ULONG)pThis->InternalAddRef();
  1469. }
  1470.  
  1471. STDMETHODIMP_(ULONG) COleControlSite::XOleIPSite::Release()
  1472. {
  1473.     METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
  1474.     return (ULONG)pThis->InternalRelease();
  1475. }
  1476.  
  1477. STDMETHODIMP COleControlSite::XOleIPSite::QueryInterface(
  1478.     REFIID iid, LPVOID* ppvObj)
  1479. {
  1480.     METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
  1481.     return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
  1482. }
  1483.  
  1484. STDMETHODIMP COleControlSite::XOleIPSite::GetWindow(HWND* phWnd)
  1485. {
  1486.     METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
  1487.     *phWnd = pThis->m_pCtrlCont->m_pWnd->GetSafeHwnd();
  1488.     return *phWnd != NULL ? S_OK : E_FAIL;
  1489. }
  1490.  
  1491. STDMETHODIMP COleControlSite::XOleIPSite::ContextSensitiveHelp(BOOL)
  1492. {
  1493.     return E_NOTIMPL;
  1494. }
  1495.  
  1496. STDMETHODIMP COleControlSite::XOleIPSite::CanInPlaceActivate()
  1497. {
  1498.     return S_OK;
  1499. }
  1500.  
  1501. STDMETHODIMP COleControlSite::XOleIPSite::OnInPlaceActivate()
  1502. {
  1503.     return S_OK;
  1504. }
  1505.  
  1506. STDMETHODIMP COleControlSite::XOleIPSite::OnUIActivate()
  1507. {
  1508.     METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
  1509.     pThis->m_pCtrlCont->OnUIActivate(pThis);
  1510.     return S_OK;
  1511. }
  1512.  
  1513. STDMETHODIMP COleControlSite::XOleIPSite::GetWindowContext(
  1514.     LPOLEINPLACEFRAME* ppFrame, LPOLEINPLACEUIWINDOW* ppDoc, LPRECT prectPos,
  1515.     LPRECT prectClip, LPOLEINPLACEFRAMEINFO pFrameInfo)
  1516. {
  1517.     METHOD_PROLOGUE_EX(COleControlSite, OleIPSite)
  1518.     ASSERT_VALID(pThis->m_pCtrlCont);
  1519.     ASSERT_VALID(pThis->m_pCtrlCont->m_pWnd);
  1520.  
  1521.     ASSERT(AfxIsValidAddress(ppFrame, sizeof(LPOLEINPLACEFRAME)));
  1522.     ASSERT((ppDoc == NULL) ||
  1523.         AfxIsValidAddress(ppDoc, sizeof(LPOLEINPLACEUIWINDOW)));
  1524.     ASSERT(AfxIsValidAddress(prectPos, sizeof(RECT)));
  1525.     ASSERT(AfxIsValidAddress(prectClip, sizeof(RECT)));
  1526.     ASSERT(AfxIsValidAddress(pFrameInfo, pFrameInfo->cb));
  1527.  
  1528.     //WINBUG: This is a temporary patch for IE3 beta.  When IE3 is fixed, this
  1529.     // assert can be re-enabled.  Otherwise it fires everytime you browse via
  1530.     // the CWebBrowser control.
  1531.     //
  1532.     //  ASSERT(pFrameInfo->cb >= offsetof(OLEINPLACEFRAMEINFO, cAccelEntries) +
  1533.     //          sizeof(int));
  1534.  
  1535.     // There is no separate doc window
  1536.     if (ppDoc != NULL)
  1537.         *ppDoc = NULL;
  1538.  
  1539.     // Set pointer to frame
  1540.     if (FAILED(pThis->m_pCtrlCont->InternalQueryInterface(
  1541.         &IID_IOleInPlaceFrame, (LPVOID*)ppFrame)))
  1542.         return E_FAIL;
  1543.  
  1544.     // Fill in position and clip rectangles
  1545.     CWnd* pWndContainer = pThis->m_pCtrlCont->m_pWnd;
  1546.     CopyRect(prectPos, pThis->m_rect);
  1547.     pWndContainer->GetClientRect(prectClip);
  1548.  
  1549.     // Fill in frame info
  1550.     pFrameInfo->fMDIApp = FALSE;
  1551.     pFrameInfo->hwndFrame = pWndContainer->GetSafeHwnd();
  1552.     pFrameInfo->haccel = NULL;
  1553.     pFrameInfo->cAccelEntries = 0;
  1554.  
  1555.     return S_OK;
  1556. }
  1557.  
  1558. STDMETHODIMP COleControlSite::XOleIPSite::Scroll(SIZE)
  1559. {
  1560.     return S_FALSE;
  1561. }
  1562.  
  1563. STDMETHODIMP COleControlSite::XOleIPSite::OnUIDeactivate(BOOL)
  1564. {
  1565.     METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
  1566.     pThis->m_pCtrlCont->OnUIDeactivate(pThis);
  1567.     return S_OK;
  1568. }
  1569.  
  1570. STDMETHODIMP COleControlSite::XOleIPSite::OnInPlaceDeactivate()
  1571. {
  1572.     METHOD_PROLOGUE_EX(COleControlSite, OleIPSite)
  1573.     pThis->DetachWindow();
  1574.     return S_OK;
  1575. }
  1576.  
  1577. STDMETHODIMP COleControlSite::XOleIPSite::DiscardUndoState()
  1578. {
  1579.     return S_OK;
  1580. }
  1581.  
  1582. STDMETHODIMP COleControlSite::XOleIPSite::DeactivateAndUndo()
  1583. {
  1584.     METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
  1585.     pThis->m_pInPlaceObject->UIDeactivate();
  1586.     return S_OK;
  1587. }
  1588.  
  1589. STDMETHODIMP COleControlSite::XOleIPSite::OnPosRectChange(LPCRECT lprcPosRect)
  1590. {
  1591.     METHOD_PROLOGUE_EX_(COleControlSite, OleIPSite)
  1592.     CRect rectClip;
  1593.     pThis->m_pCtrlCont->m_pWnd->GetClientRect(rectClip);
  1594.     pThis->m_rect = lprcPosRect;
  1595.     return pThis->m_pInPlaceObject->SetObjectRects(pThis->m_rect, rectClip);
  1596. }
  1597.  
  1598.  
  1599. /////////////////////////////////////////////////////////////////////////////
  1600. // COleControlSite::XOleControlSite
  1601.  
  1602. STDMETHODIMP_(ULONG) COleControlSite::XOleControlSite::AddRef()
  1603. {
  1604.     METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
  1605.     return (ULONG)pThis->InternalAddRef();
  1606. }
  1607.  
  1608. STDMETHODIMP_(ULONG) COleControlSite::XOleControlSite::Release()
  1609. {
  1610.     METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
  1611.     return (ULONG)pThis->InternalRelease();
  1612. }
  1613.  
  1614. STDMETHODIMP COleControlSite::XOleControlSite::QueryInterface(
  1615.     REFIID iid, LPVOID* ppvObj)
  1616. {
  1617.     METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
  1618.     return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
  1619. }
  1620.  
  1621. STDMETHODIMP COleControlSite::XOleControlSite::OnControlInfoChanged()
  1622. {
  1623.     METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
  1624.     pThis->GetControlInfo();
  1625.     return NOERROR;
  1626. }
  1627.  
  1628. STDMETHODIMP COleControlSite::XOleControlSite::LockInPlaceActive(BOOL)
  1629. {
  1630.     return E_NOTIMPL;
  1631. }
  1632.  
  1633. STDMETHODIMP COleControlSite::XOleControlSite::GetExtendedControl(
  1634.     LPDISPATCH*)
  1635. {
  1636.     return E_NOTIMPL;
  1637. }
  1638.  
  1639. STDMETHODIMP COleControlSite::XOleControlSite::TransformCoords(
  1640.     POINTL* pptHimetric, POINTF* pptContainer, DWORD dwFlags)
  1641. {
  1642.     METHOD_PROLOGUE_EX_(COleControlSite, OleControlSite)
  1643.     HRESULT hr = NOERROR;
  1644.  
  1645.     HDC hDC = ::GetDC(pThis->m_hWnd);
  1646.     ::SetMapMode(hDC, MM_HIMETRIC);
  1647.     POINT rgptConvert[2];
  1648.     rgptConvert[0].x = 0;
  1649.     rgptConvert[0].y = 0;
  1650.  
  1651.     if (dwFlags & XFORMCOORDS_HIMETRICTOCONTAINER)
  1652.     {
  1653.         rgptConvert[1].x = pptHimetric->x;
  1654.         rgptConvert[1].y = pptHimetric->y;
  1655.         ::LPtoDP(hDC, rgptConvert, 2);
  1656.         if (dwFlags & XFORMCOORDS_SIZE)
  1657.         {
  1658.             pptContainer->x = (float)(rgptConvert[1].x - rgptConvert[0].x);
  1659.             pptContainer->y = (float)(rgptConvert[0].y - rgptConvert[1].y);
  1660.         }
  1661.         else if (dwFlags & XFORMCOORDS_POSITION)
  1662.         {
  1663.             pptContainer->x = (float)rgptConvert[1].x;
  1664.             pptContainer->y = (float)rgptConvert[1].y;
  1665.         }
  1666.         else
  1667.         {
  1668.             hr = E_INVALIDARG;
  1669.         }
  1670.     }
  1671.     else if (dwFlags & XFORMCOORDS_CONTAINERTOHIMETRIC)
  1672.     {
  1673.         rgptConvert[1].x = (int)(pptContainer->x);
  1674.         rgptConvert[1].y = (int)(pptContainer->y);
  1675.         ::DPtoLP(hDC, rgptConvert, 2);
  1676.         if (dwFlags & XFORMCOORDS_SIZE)
  1677.         {
  1678.             pptHimetric->x = rgptConvert[1].x - rgptConvert[0].x;
  1679.             pptHimetric->y = rgptConvert[0].y - rgptConvert[1].y;
  1680.         }
  1681.         else if (dwFlags & XFORMCOORDS_POSITION)
  1682.         {
  1683.             pptHimetric->x = rgptConvert[1].x;
  1684.             pptHimetric->y = rgptConvert[1].y;
  1685.         }
  1686.         else
  1687.         {
  1688.             hr = E_INVALIDARG;
  1689.         }
  1690.     }
  1691.     else
  1692.     {
  1693.         hr = E_INVALIDARG;
  1694.     }
  1695.  
  1696.     ::ReleaseDC(pThis->m_hWnd, hDC);
  1697.  
  1698.     return hr;
  1699. }
  1700.  
  1701. STDMETHODIMP COleControlSite::XOleControlSite::TranslateAccelerator(
  1702.     LPMSG, DWORD)
  1703. {
  1704.     return E_NOTIMPL;
  1705. }
  1706.  
  1707. STDMETHODIMP COleControlSite::XOleControlSite::OnFocus(BOOL)
  1708. {
  1709.     return S_OK;
  1710. }
  1711.  
  1712. STDMETHODIMP COleControlSite::XOleControlSite::ShowPropertyFrame()
  1713. {
  1714.     return E_NOTIMPL;
  1715. }
  1716.  
  1717. /////////////////////////////////////////////////////////////////////////////
  1718. // COleControlSite::XAmbientProps
  1719.  
  1720. STDMETHODIMP_(ULONG) COleControlSite::XAmbientProps::AddRef()
  1721. {
  1722.     METHOD_PROLOGUE_EX_(COleControlSite, AmbientProps)
  1723.     return (ULONG)pThis->InternalAddRef();
  1724. }
  1725.  
  1726. STDMETHODIMP_(ULONG) COleControlSite::XAmbientProps::Release()
  1727. {
  1728.     METHOD_PROLOGUE_EX_(COleControlSite, AmbientProps)
  1729.     return (ULONG)pThis->InternalRelease();
  1730. }
  1731.  
  1732. STDMETHODIMP COleControlSite::XAmbientProps::QueryInterface(
  1733.     REFIID iid, LPVOID* ppvObj)
  1734. {
  1735.     METHOD_PROLOGUE_EX_(COleControlSite, AmbientProps)
  1736.     return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
  1737. }
  1738.  
  1739. STDMETHODIMP COleControlSite::XAmbientProps::GetTypeInfoCount(
  1740.     unsigned int*)
  1741. {
  1742.     return E_NOTIMPL;
  1743. }
  1744.  
  1745. STDMETHODIMP COleControlSite::XAmbientProps::GetTypeInfo(
  1746.     unsigned int, LCID, ITypeInfo**)
  1747. {
  1748.     return E_NOTIMPL;
  1749. }
  1750.  
  1751. STDMETHODIMP COleControlSite::XAmbientProps::GetIDsOfNames(
  1752.     REFIID, LPOLESTR*, unsigned int, LCID, DISPID*)
  1753. {
  1754.     return E_NOTIMPL;
  1755. }
  1756.  
  1757. STDMETHODIMP COleControlSite::XAmbientProps::Invoke(
  1758.     DISPID dispid, REFIID, LCID, unsigned short wFlags,
  1759.     DISPPARAMS* pDispParams, VARIANT* pvarResult,
  1760.     EXCEPINFO*, unsigned int*)
  1761. {
  1762.     UNUSED(wFlags);
  1763.     UNUSED(pDispParams);
  1764.  
  1765.     METHOD_PROLOGUE_EX(COleControlSite, AmbientProps)
  1766.     ASSERT(wFlags & DISPATCH_PROPERTYGET);
  1767.     ASSERT(pDispParams->cArgs == 0);
  1768.  
  1769.     ASSERT(pThis->m_pCtrlCont != NULL);
  1770.     ASSERT(pThis->m_pCtrlCont->m_pWnd != NULL);
  1771.  
  1772.     return pThis->m_pCtrlCont->m_pWnd->OnAmbientProperty(pThis, dispid, pvarResult) ?
  1773.         S_OK : DISP_E_MEMBERNOTFOUND;
  1774. }
  1775.  
  1776.  
  1777. /////////////////////////////////////////////////////////////////////////////
  1778. // COleControlSite::XPropertyNotifySink
  1779.  
  1780. STDMETHODIMP COleControlSite::XPropertyNotifySink::QueryInterface(
  1781.     REFIID iid, LPVOID* ppvObj)
  1782. {
  1783.     METHOD_PROLOGUE_EX_(COleControlSite, PropertyNotifySink)
  1784.  
  1785.     if (IsEqualIID(iid, IID_IUnknown) ||
  1786.         IsEqualIID(iid, IID_IPropertyNotifySink))
  1787.     {
  1788.         *ppvObj = this;
  1789.         AddRef();
  1790.         return S_OK;
  1791.     }
  1792.     else
  1793.     {
  1794.         return E_NOINTERFACE;
  1795.     }
  1796. }
  1797.  
  1798. STDMETHODIMP_(ULONG) COleControlSite::XPropertyNotifySink::AddRef()
  1799. {
  1800.     return 1;
  1801. }
  1802.  
  1803. STDMETHODIMP_(ULONG) COleControlSite::XPropertyNotifySink::Release()
  1804. {
  1805.     return 0;
  1806. }
  1807.  
  1808. STDMETHODIMP COleControlSite::XPropertyNotifySink::OnChanged(
  1809.     DISPID dispid)
  1810. {
  1811.     METHOD_PROLOGUE_EX(COleControlSite, PropertyNotifySink)
  1812.  
  1813.     // If we are currently updating the control ignore notifications
  1814.     if (pThis->m_bIgnoreNotify)
  1815.         return S_OK;
  1816.  
  1817.     // Give user chance to override
  1818.     if (!pThis->m_pDataSourceControl)
  1819.     {
  1820.         AFX_EVENT event(AFX_EVENT::propChanged, dispid);
  1821.         pThis->OnEvent(&event);
  1822.         if (event.m_hResult != S_OK)
  1823.             return event.m_hResult;
  1824.     }
  1825.  
  1826.     if (pThis->m_defdispid == dispid)
  1827.     {
  1828.         ::VariantClear(&pThis->m_varResult);
  1829.  
  1830.         HRESULT hRes;
  1831.         LPDISPATCH pDispatch = NULL;
  1832.         hRes = pThis->m_pObject->QueryInterface(IID_IDispatch, (LPVOID *) &pDispatch);
  1833.         if (FAILED(hRes))
  1834.             return S_OK;
  1835.  
  1836.         EXCEPINFO excepinfo;
  1837.         memset(&excepinfo, 0, sizeof(EXCEPINFO));
  1838.         UINT uArgErr;
  1839.         DISPPARAMS dispparamsGetProp;
  1840.         memset (&dispparamsGetProp, 0, sizeof(DISPPARAMS));
  1841.         hRes = pDispatch->Invoke(dispid, IID_NULL, 0, INVOKE_PROPERTYGET, &dispparamsGetProp,
  1842.                 &pThis->m_varResult, &excepinfo, &uArgErr); //Get bound control property
  1843.  
  1844.         if (excepinfo.bstrSource)
  1845.             SysFreeString(excepinfo.bstrSource);
  1846.         if (excepinfo.bstrDescription)
  1847.             SysFreeString(excepinfo.bstrDescription);
  1848.         if (excepinfo.bstrHelpFile)
  1849.             SysFreeString(excepinfo.bstrHelpFile);
  1850.  
  1851.         pDispatch->Release();
  1852.  
  1853.         if (FAILED(hRes))
  1854.             return S_OK;
  1855.  
  1856.         pThis->m_bIsDirty = TRUE;
  1857.     }
  1858.  
  1859.     return S_OK;
  1860. }
  1861.  
  1862. STDMETHODIMP COleControlSite::XPropertyNotifySink::OnRequestEdit(
  1863.     DISPID dispid)
  1864. {
  1865.     METHOD_PROLOGUE_EX(COleControlSite, PropertyNotifySink)
  1866.  
  1867.     // If we are currently updating the control ignore notifications
  1868.     if (pThis->m_bIgnoreNotify)
  1869.         return S_OK;
  1870.  
  1871.     // If not bound fire regular MFC event
  1872.     if (!pThis->m_pDataSourceControl)
  1873.     {
  1874.         AFX_EVENT event(AFX_EVENT::propRequest, dispid);
  1875.         pThis->OnEvent(&event);
  1876.         if (event.m_hResult != S_OK)
  1877.             return event.m_hResult;
  1878.     }
  1879.  
  1880.     // Currently we only support Optimistic binding ala VB4
  1881.     // In this model, requests always succeed
  1882.     return S_OK;
  1883. }
  1884.  
  1885. /////////////////////////////////////////////////////////////////////////////
  1886. // COleControlSite::XEventSink
  1887.  
  1888. STDMETHODIMP_(ULONG) COleControlSite::XEventSink::AddRef()
  1889. {
  1890.     return 1;
  1891. }
  1892.  
  1893. STDMETHODIMP_(ULONG) COleControlSite::XEventSink::Release()
  1894. {
  1895.     return 0;
  1896. }
  1897.  
  1898. STDMETHODIMP COleControlSite::XEventSink::QueryInterface(
  1899.     REFIID iid, LPVOID* ppvObj)
  1900. {
  1901.     METHOD_PROLOGUE_EX_(COleControlSite, EventSink)
  1902.  
  1903.     if (IsEqualIID(iid, IID_IUnknown) ||
  1904.         IsEqualIID(iid, IID_IDispatch) ||
  1905.         IsEqualIID(iid, pThis->m_iidEvents))
  1906.     {
  1907.         *ppvObj = this;
  1908.         AddRef();
  1909.         return S_OK;
  1910.     }
  1911.     else
  1912.     {
  1913.         return E_NOINTERFACE;
  1914.     }
  1915. }
  1916.  
  1917. STDMETHODIMP COleControlSite::XEventSink::GetTypeInfoCount(
  1918.     unsigned int*)
  1919. {
  1920.     return E_NOTIMPL;
  1921. }
  1922.  
  1923. STDMETHODIMP COleControlSite::XEventSink::GetTypeInfo(
  1924.     unsigned int, LCID, ITypeInfo**)
  1925. {
  1926.     return E_NOTIMPL;
  1927. }
  1928.  
  1929. STDMETHODIMP COleControlSite::XEventSink::GetIDsOfNames(
  1930.     REFIID, LPOLESTR*, unsigned int, LCID, DISPID*)
  1931. {
  1932.     return E_NOTIMPL;
  1933. }
  1934.  
  1935. STDMETHODIMP COleControlSite::XEventSink::Invoke(
  1936.     DISPID dispid, REFIID, LCID, unsigned short wFlags,
  1937.     DISPPARAMS* pDispParams, VARIANT* pvarResult,
  1938.     EXCEPINFO* pExcepInfo, unsigned int* puArgError)
  1939. {
  1940.     UNUSED(wFlags);
  1941.  
  1942.     METHOD_PROLOGUE_EX(COleControlSite, EventSink)
  1943.     ASSERT(pThis->m_pCtrlCont != NULL);
  1944.     ASSERT(pThis->m_pCtrlCont->m_pWnd != NULL);
  1945.     ASSERT(wFlags == DISPATCH_METHOD);
  1946.  
  1947.     AFX_EVENT event(AFX_EVENT::event, dispid, pDispParams, pExcepInfo,
  1948.         puArgError);
  1949.  
  1950.     pThis->OnEvent(&event);
  1951.  
  1952.     if (pvarResult != NULL)
  1953.         ::VariantClear(pvarResult);
  1954.  
  1955.     return event.m_hResult;
  1956. }
  1957.  
  1958. /////////////////////////////////////////////////////////////////////////////
  1959. // CDataSourceControl
  1960.  
  1961.  
  1962. CDataSourceControl::CDataSourceControl(COleControlSite *pClientSite) :
  1963.     m_pClientSite(pClientSite),
  1964.     m_pCursorMove(NULL),
  1965.     m_pCursorUpdateARow(NULL),
  1966.     m_pMetaRowData(NULL),
  1967.     m_pVarData(NULL),
  1968.     m_nColumns(0),
  1969.     m_nBindings(0),
  1970.     m_pColumnBindings(NULL),
  1971.     m_pValues(NULL),
  1972.     m_bUpdateInProgress(FALSE),
  1973.     m_pDataSource(NULL),
  1974.     m_pRowPosition(NULL),
  1975.     m_pRowset(NULL),
  1976.     m_pDynamicAccessor(NULL),
  1977.     m_dwRowsetNotify(0)
  1978. {
  1979.     ASSERT(pClientSite);
  1980. }
  1981.  
  1982. CDataSourceControl::~CDataSourceControl()
  1983. {
  1984.     // cancel ole/db notifications
  1985.     if (m_dwRowsetNotify != 0 && m_pRowset != NULL)
  1986.     {
  1987.         LPCONNECTIONPOINTCONTAINER pConnPtCont;
  1988.  
  1989.         if (SUCCEEDED(m_pRowset->m_spRowset->QueryInterface(IID_IConnectionPointContainer,
  1990.                 (LPVOID*)&pConnPtCont)))
  1991.         {
  1992.             ASSERT(pConnPtCont != NULL);
  1993.             LPCONNECTIONPOINT pConnPt = NULL;
  1994.  
  1995.             if (SUCCEEDED(pConnPtCont->FindConnectionPoint(IID_IRowsetNotify, &pConnPt)))
  1996.             {
  1997.                 ASSERT(pConnPt != NULL);
  1998.                 pConnPt->Unadvise(m_dwRowsetNotify);
  1999.                 pConnPt->Release();
  2000.             }
  2001.  
  2002.             pConnPtCont->Release();
  2003.         }
  2004.     }
  2005.  
  2006.     // Now go through all cursor bound properties
  2007.     while (!m_CursorBoundProps.IsEmpty())
  2008.     {
  2009.         CDataBoundProperty* pProp = (CDataBoundProperty*) m_CursorBoundProps.GetHead();
  2010.         pProp->m_pClientSite->BindProperty(pProp->m_dispid, NULL);
  2011.         pProp->m_pClientSite->m_pDSCSite = NULL;
  2012.     }
  2013.     m_CursorBoundProps.RemoveAll();
  2014.  
  2015.     if (m_pValues)
  2016.     {
  2017.         for (int i=0; i<m_nBindings; i++)
  2018.             ::VariantClear(&m_pValues[i]);
  2019.         if (m_nBindings)
  2020.         {
  2021.             delete[] m_pColumnBindings;
  2022.             delete[] m_pValues;
  2023.         }
  2024.     }
  2025.  
  2026.     if (m_pCursorMove)
  2027.         m_pCursorMove->Release();
  2028.  
  2029.     if (m_pCursorUpdateARow)
  2030.         m_pCursorUpdateARow->Release();
  2031.  
  2032.     if (m_pMetaRowData)
  2033.     {
  2034.         for (int nCol=0; nCol<m_nColumns; nCol++)
  2035.         {
  2036.             POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
  2037.             while (pos)
  2038.             {
  2039.                 COleControlSite* pSite = (COleControlSite *)
  2040.                     m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
  2041.                 pSite->m_pDSCSite = NULL;
  2042.             }
  2043.             m_pMetaRowData[nCol].m_pClientList->RemoveAll();
  2044.             delete m_pMetaRowData[nCol].m_pClientList;
  2045.         }
  2046.         ::CoTaskMemFree(m_pMetaRowData);
  2047.     }
  2048.     if (m_pVarData)
  2049.         ::CoTaskMemFree(m_pVarData);
  2050.  
  2051.     if(m_pDynamicAccessor != NULL)
  2052.     {
  2053.         m_pDynamicAccessor->ReleaseAccessors(m_pRowset->m_spRowset);
  2054.         m_pDynamicAccessor->Close();
  2055.     }
  2056.     delete m_pDynamicAccessor;
  2057.     delete m_pRowset;
  2058.     if (m_pRowPosition != NULL)
  2059.         m_pRowPosition->Release();
  2060.     if (m_pDataSource != NULL)
  2061.         m_pDataSource->Release();
  2062. }
  2063.  
  2064. interface IVBDSC : public IUnknown
  2065. {
  2066. public:
  2067.     virtual HRESULT STDMETHODCALLTYPE CancelUnload(BOOL __RPC_FAR* pfCancel) = 0;
  2068.     virtual HRESULT STDMETHODCALLTYPE Error(DWORD dwErr, BOOL __RPC_FAR* pfShowError) = 0;
  2069.     virtual HRESULT STDMETHODCALLTYPE CreateCursor(ICursor __RPC_FAR* __RPC_FAR* ppCursor) = 0;
  2070. };
  2071.  
  2072. const IID IID_IVBDSC = {0x1ab42240,0x8c70,0x11ce,{0x94,0x21,0x0,0xaa,0x0,0x62,0xbe,0x57}};
  2073. const IID CLSID_DataAdapter = {0x3A08E130L,0x8F65,0x11D0,{0x94,0x84,0x00,0xA0,0xC9,0x11,0x10,0xED}};
  2074.  
  2075. HRESULT CDataSourceControl::Initialize()
  2076. {
  2077.     // The following is a work around for RDC behaviour when on an invisible dlg
  2078.     // When the dlg is invisible it cannot display the ODBC connect dialog
  2079.     // So check if visible, if not make it so and move it to the center
  2080.     // of the screen with null size. Then do the connect dialog
  2081.     // Finally put it all back like it was.
  2082.     CWnd* pParent = m_pClientSite->m_pWndCtrl->GetTopLevelParent();
  2083.     BOOL bHidden = !pParent->IsWindowVisible();
  2084.     CRect rcParent;
  2085.     if (bHidden)
  2086.     {
  2087.         CRect rcDesktop;
  2088.         CWnd::GetDesktopWindow()->GetWindowRect(&rcDesktop);
  2089.         pParent->GetWindowRect(&rcParent);
  2090.         pParent->MoveWindow((rcDesktop.right - rcDesktop.left)/2, (rcDesktop.bottom - rcDesktop.top)/2, 0, 0, FALSE);
  2091.         pParent->ShowWindow(SW_SHOWNORMAL);
  2092.     }
  2093.     IVBDSC* pDSC;
  2094.     HRESULT hRes;
  2095.  
  2096.     hRes = m_pClientSite->m_pObject->QueryInterface(IID_IDataSource, (void**)&m_pDataSource);
  2097.     if (SUCCEEDED(hRes))
  2098.     {
  2099.         hRes = m_pDataSource->GetDataMember(NULL, &IID_IRowPosition, (IUnknown**)&m_pRowPosition);
  2100.         if (m_pRowPosition == NULL)
  2101.             hRes = E_POINTER;
  2102.  
  2103.         if (FAILED(hRes))
  2104.         {
  2105.             if (bHidden)
  2106.             {
  2107.                 pParent->MoveWindow(rcParent.left, rcParent.top, rcParent.right - rcParent.left, rcParent.bottom - rcParent.top, FALSE);
  2108.                 pParent->ShowWindow(SW_HIDE);
  2109.             }
  2110.             return hRes;
  2111.         }
  2112.     }
  2113.     else
  2114.     {
  2115.         hRes = m_pClientSite->m_pObject->QueryInterface(IID_IVBDSC, (void**)&pDSC);
  2116.         if (FAILED(hRes))
  2117.             return hRes;
  2118.         ICursor* pCursor;
  2119.         pDSC->CreateCursor(&pCursor);
  2120.         pDSC->Release();
  2121.         if (!pCursor)
  2122.             return E_FAIL;
  2123.  
  2124.         hRes = pCursor->QueryInterface(IID_ICursorMove,
  2125.             (LPVOID *)&m_pCursorMove);
  2126.  
  2127.         pCursor->Release();
  2128.  
  2129.         if (FAILED(hRes))
  2130.             return hRes;
  2131.  
  2132.         hRes = m_pCursorMove->QueryInterface(IID_ICursorUpdateARow,
  2133.             (LPVOID *)&m_pCursorUpdateARow);
  2134.     }
  2135.  
  2136.     hRes = GetMetaData();
  2137.  
  2138.     if (bHidden)
  2139.     {
  2140.         pParent->MoveWindow(rcParent.left, rcParent.top, rcParent.right - rcParent.left, rcParent.bottom - rcParent.top, FALSE);
  2141.         pParent->ShowWindow(SW_HIDE);
  2142.     }
  2143.  
  2144.     return hRes;
  2145. }
  2146.  
  2147. IUnknown* CDataSourceControl::GetCursor()
  2148. {
  2149.     ASSERT(m_pClientSite != NULL);
  2150.  
  2151.     if (m_pDataSource != NULL)
  2152.     {
  2153.         if(m_pRowset != NULL)
  2154.             return m_pDataSource;
  2155.         return NULL;
  2156.     }
  2157.  
  2158.     ICursor* pCursor;
  2159.     if (!m_pCursorMove)
  2160.     {
  2161.         IVBDSC* pDSC;
  2162.         HRESULT hRes;
  2163.         hRes = m_pClientSite->m_pObject->QueryInterface(IID_IVBDSC, (void**)&pDSC);
  2164.         if (FAILED(hRes))
  2165.             return NULL;
  2166.         pDSC->CreateCursor(&pCursor);
  2167.         pDSC->Release();
  2168.         if (!pCursor)
  2169.             return NULL;
  2170.         return pCursor;
  2171.     }
  2172.     if (SUCCEEDED(m_pCursorMove->QueryInterface(IID_ICursor, (LPVOID *) &pCursor)))
  2173.             return pCursor;
  2174.  
  2175.     ASSERT(FALSE); // DSC Cursor Not Found
  2176.     return NULL;
  2177. }
  2178.  
  2179. HRESULT CDataSourceControl::GetMetaData()
  2180. {
  2181.     HRESULT hRes;
  2182.     METAROWTYPE* pOldMetaData = m_pMetaRowData;
  2183.     int nOldColumns = m_nColumns;
  2184.  
  2185.     if (m_pDataSource != NULL)
  2186.     {
  2187.         IRowset* pRowset;
  2188.  
  2189.         hRes = m_pRowPosition->GetRowset(IID_IRowset, reinterpret_cast<IUnknown**>(&pRowset));
  2190.         if (FAILED(hRes))
  2191.             return hRes;
  2192.  
  2193.         {
  2194.             LPCONNECTIONPOINTCONTAINER pConnPtCont;
  2195.  
  2196.             if (SUCCEEDED(pRowset->QueryInterface(IID_IConnectionPointContainer,
  2197.                     (LPVOID*)&pConnPtCont)))
  2198.             {
  2199.                 ASSERT(pConnPtCont != NULL);
  2200.                 LPCONNECTIONPOINT pConnPt = NULL;
  2201.  
  2202.                 if (SUCCEEDED(pConnPtCont->FindConnectionPoint(IID_IRowsetNotify, &pConnPt)))
  2203.                 {
  2204.                     ASSERT(pConnPt != NULL);
  2205.                     pConnPt->Advise(&m_pClientSite->m_xRowsetNotify, &m_dwRowsetNotify);
  2206.                     pConnPt->Release();
  2207.                 }
  2208.  
  2209.                 pConnPtCont->Release();
  2210.             }
  2211.         }
  2212.  
  2213.         m_pRowset = new CRowset(pRowset);
  2214.         pRowset->Release();
  2215.         m_pRowset->SetupOptionalRowsetInterfaces();
  2216.         m_pDynamicAccessor = new CDynamicAccessor;
  2217.         m_pDynamicAccessor->BindColumns(m_pRowset->m_spRowset);
  2218.         m_pRowset->SetAccessor(m_pDynamicAccessor);
  2219.         m_nColumns = m_pDynamicAccessor->GetColumnCount();
  2220.         m_pMetaRowData = (METAROWTYPE*)::CoTaskMemAlloc(sizeof(METAROWTYPE) * m_nColumns);
  2221.         ASSERT(m_pMetaRowData);
  2222.         memset(m_pMetaRowData, 0, sizeof(METAROWTYPE) * m_nColumns);
  2223.         m_pRowset->MoveFirst();
  2224.         m_pRowset->ReleaseRows();
  2225.     }
  2226.     else
  2227.     {
  2228.         ULONG nRows;
  2229.         ICursor* pCursor = (LPCURSOR)m_pCursorMove;
  2230.         ICursor* pColumnCursor;
  2231.  
  2232.         if (pCursor == NULL)
  2233.             return S_OK;
  2234.  
  2235.         hRes = pCursor->GetColumnsCursor(IID_ICursor, (IUnknown **) &pColumnCursor, &nRows);
  2236.         if (FAILED(hRes))
  2237.             return hRes;
  2238.  
  2239.         DBCOLUMNBINDING MetaColumns[2];
  2240.         CopyColumnID(&MetaColumns[0].columnID, &COLUMN_COLUMNID);
  2241.         MetaColumns[0].obData = offsetof(METAROWTYPE, idColumnID);
  2242.         MetaColumns[0].cbMaxLen = DB_NOMAXLENGTH;
  2243.         MetaColumns[0].obInfo = offsetof(METAROWTYPE, dwColumnID);
  2244.         MetaColumns[0].obVarDataLen = DB_NOVALUE;
  2245.         MetaColumns[0].dwBinding = DBBINDING_DEFAULT;
  2246.         MetaColumns[0].dwDataType = DBTYPE_COLUMNID;
  2247.  
  2248.         CopyColumnID(&MetaColumns[1].columnID, &COLUMN_NAME);
  2249.         MetaColumns[1].obData = offsetof(METAROWTYPE, lpstrName);
  2250.         MetaColumns[1].cbMaxLen = DB_NOMAXLENGTH;
  2251.         MetaColumns[1].obInfo = offsetof(METAROWTYPE, dwName);
  2252.         MetaColumns[1].obVarDataLen = DB_NOVALUE;
  2253.         MetaColumns[1].dwBinding = DBBINDING_DEFAULT;
  2254.         MetaColumns[1].dwDataType = VT_LPSTR;
  2255.  
  2256.         hRes = pColumnCursor->SetBindings(2, MetaColumns, sizeof(METAROWTYPE),
  2257.             DBCOLUMNBINDOPTS_REPLACE);
  2258.         if (FAILED(hRes))
  2259.         {
  2260.             pColumnCursor->Release();
  2261.             return hRes;
  2262.         }
  2263.  
  2264.         DBFETCHROWS FetchRows;
  2265.         FetchRows.cRowsRequested = nRows;
  2266.         FetchRows.dwFlags = DBROWFETCH_CALLEEALLOCATES;
  2267.         FetchRows.pData = NULL;
  2268.         FetchRows.pVarData = NULL;
  2269.         FetchRows.cbVarData = 0;
  2270.  
  2271.         LARGE_INTEGER dlZero;
  2272.         LISet32(dlZero, 0);
  2273.         hRes = pColumnCursor->GetNextRows(dlZero, &FetchRows);
  2274.         if (FAILED(hRes))
  2275.         {
  2276.             pColumnCursor->Release();
  2277.             return hRes;
  2278.         }
  2279.  
  2280.         m_pMetaRowData = (METAROWTYPE *)FetchRows.pData;
  2281.         ASSERT(m_pMetaRowData);
  2282.         nRows = FetchRows.cRowsReturned;       // in case it changed
  2283.         m_pVarData = FetchRows.pVarData;
  2284.  
  2285.         m_nColumns = nRows;
  2286.  
  2287.         pColumnCursor->Release();
  2288.     }
  2289.  
  2290.     for (int nCol=0; nCol<m_nColumns; nCol++)
  2291.         m_pMetaRowData[nCol].m_pClientList = new CPtrList;
  2292.  
  2293.     // re-establish all bound property sites and then delete old meta-data
  2294.     if (pOldMetaData != NULL)
  2295.     {
  2296.         for (int nCol=0; nCol<nOldColumns; nCol++)
  2297.         {
  2298.             POSITION pos = pOldMetaData[nCol].m_pClientList->GetHeadPosition();
  2299.             while (pos)
  2300.             {
  2301.                 COleControlSite* pSite = (COleControlSite *)
  2302.                     m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
  2303.                 BindProp(pSite, TRUE);
  2304.             }
  2305.             pOldMetaData[nCol].m_pClientList->RemoveAll();
  2306.             delete pOldMetaData[nCol].m_pClientList;
  2307.         }
  2308.         ::CoTaskMemFree(pOldMetaData);
  2309.     }
  2310.  
  2311.     return hRes;
  2312. }
  2313.  
  2314. BOOL CDataSourceControl::CopyColumnID(
  2315.     DBCOLUMNID* pcidDst, DBCOLUMNID const *pcidSrc)
  2316. {
  2317.     pcidDst->dwKind = pcidSrc->dwKind;
  2318.  
  2319.     switch (pcidSrc->dwKind)
  2320.     {
  2321.     case DBCOLKIND_GUID_NUMBER:
  2322.         pcidDst->guid = pcidSrc->guid;
  2323.         pcidDst->lNumber = pcidSrc->lNumber;
  2324.         break;
  2325.     case DBCOLKIND_GUID_NAME:
  2326.         pcidDst->guid = pcidSrc->guid;
  2327.         // fall through
  2328.     case DBCOLKIND_NAME:
  2329.         pcidDst->lpdbsz = (LPDBSTR) ::CoTaskMemAlloc(sizeof(DBCHAR) * (ldbstrlen(pcidSrc->lpdbsz) + 1));
  2330.         if (!pcidDst->lpdbsz)
  2331.             return FALSE;
  2332.         ldbstrcpy(pcidDst->lpdbsz, pcidSrc->lpdbsz);
  2333.         break;
  2334.     }
  2335.     return TRUE;
  2336. }
  2337.  
  2338. // Make a bound control/bound property a consumer to a particular column in this DSC
  2339. void CDataSourceControl::BindProp(COleControlSite* pClientSite, BOOL bBind)
  2340. {
  2341.     ASSERT(pClientSite);
  2342.  
  2343.     if (bBind)
  2344.     {
  2345.         BindProp(pClientSite, FALSE);
  2346.         ASSERT(pClientSite->m_pDSCSite == m_pClientSite);
  2347.         if (m_pDataSource != NULL)
  2348.         {
  2349.             for (int nCol=0; nCol<m_nColumns; nCol++)
  2350.             {
  2351.                 if (pClientSite->m_strDataField == m_pDynamicAccessor->GetColumnName(nCol + 1))
  2352.                 {
  2353.                     m_pMetaRowData[nCol].m_pClientList->AddTail(pClientSite);
  2354.                     return;
  2355.                 }
  2356.             }
  2357.         }
  2358.         else
  2359.         {
  2360.             for (int nCol=0; nCol<m_nColumns; nCol++)
  2361.             {
  2362.                 if (m_pMetaRowData[nCol].lpstrName == NULL)
  2363.                     continue;
  2364.                 if (pClientSite->m_strDataField == m_pMetaRowData[nCol].lpstrName)
  2365.                 {
  2366.                     m_pMetaRowData[nCol].m_pClientList->AddTail(pClientSite);
  2367.                     return;
  2368.                 }
  2369.             }
  2370.         }
  2371.         pClientSite->m_pDSCSite = NULL;
  2372.         return;
  2373.     }
  2374.     UpdateCursor();
  2375.     // UnBind
  2376.     for (int nCol=0; nCol<m_nColumns; nCol++)
  2377.     {
  2378.         POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
  2379.         POSITION prev;
  2380.         while (pos)
  2381.         {
  2382.             prev = pos;
  2383.             COleControlSite* pSite = (COleControlSite *)
  2384.                 m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
  2385.             if (pSite == pClientSite)
  2386.             {
  2387.                 m_pMetaRowData[nCol].m_pClientList->RemoveAt(prev);
  2388.                 return;
  2389.             }
  2390.         }
  2391.     }
  2392. }
  2393.  
  2394. // Make a cursor bound control property a client to this control
  2395. void CDataSourceControl::BindProp(CDataBoundProperty* pProperty, BOOL bBind)
  2396. {
  2397.     ASSERT(pProperty);
  2398.  
  2399.     if (bBind)
  2400.     {
  2401.         BindProp(pProperty, FALSE);
  2402.         m_CursorBoundProps.AddTail(pProperty);
  2403.     }
  2404.     else
  2405.     {
  2406.         UpdateCursor();
  2407.         POSITION pos = m_CursorBoundProps.Find(pProperty);
  2408.         if (pos != NULL)
  2409.             m_CursorBoundProps.RemoveAt(pos);
  2410.     }
  2411. }
  2412.  
  2413. void CDataSourceControl::BindColumns()
  2414. {
  2415.     if (m_pDataSource != NULL)
  2416.     {
  2417.         // this is done automatically by CDynamicAccessor
  2418.         GetBoundClientRow();
  2419.         UpdateControls();
  2420.         return;
  2421.     }
  2422.     if (m_pValues)
  2423.     {
  2424.         for (int i=0; i<m_nBindings; i++)
  2425.             ::VariantClear(&m_pValues[i]);
  2426.         if (m_nBindings > 0)
  2427.         {
  2428.             delete[] m_pValues;
  2429.             delete[] m_pColumnBindings;
  2430.         }
  2431.         m_pValues = NULL;
  2432.     }
  2433.     m_nBindings = 0;
  2434.     for (int nCol=0; nCol<m_nColumns; nCol++)
  2435.     {
  2436.         m_nBindings += m_pMetaRowData[nCol].m_pClientList->GetCount();
  2437.     }
  2438.     if (m_nBindings > 0)
  2439.         m_pColumnBindings = new DBCOLUMNBINDING[m_nBindings];
  2440.     int nItem = 0;
  2441.     for (nCol=0; nCol<m_nColumns; nCol++)
  2442.     {
  2443.         POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
  2444.         while (pos)
  2445.         {
  2446.             COleControlSite* pSite = (COleControlSite *)
  2447.                 m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
  2448.             CopyColumnID(&m_pColumnBindings[nItem].columnID, &m_pMetaRowData[nCol].idColumnID);
  2449.             m_pColumnBindings[nItem].obData = sizeof(VARIANT) * nItem;
  2450.             m_pColumnBindings[nItem].cbMaxLen = DB_NOMAXLENGTH;
  2451.             m_pColumnBindings[nItem].obInfo = DB_NOVALUE;
  2452.             m_pColumnBindings[nItem].obVarDataLen = DB_NOVALUE;
  2453.             m_pColumnBindings[nItem].dwBinding = DBBINDING_VARIANT;
  2454.             m_pColumnBindings[nItem].dwDataType = pSite->m_dwType;
  2455.             nItem++;
  2456.         }
  2457.     }
  2458.     m_pCursorMove->SetBindings(m_nBindings, m_pColumnBindings,
  2459.         sizeof(VARIANT) * m_nBindings, DBCOLUMNBINDOPTS_REPLACE);
  2460.  
  2461.     if (m_nBindings)
  2462.         m_pValues = new VARIANT[m_nBindings];
  2463.  
  2464.     for (int i=0; i<m_nBindings; i++)
  2465.     {
  2466.         memset(&m_pValues[i], 0, sizeof(VARIANT));
  2467.         m_pValues[i].vt = VT_EMPTY;
  2468.     }
  2469.  
  2470.     GetBoundClientRow();
  2471.     UpdateControls();
  2472. }
  2473.  
  2474. HRESULT CDataSourceControl::GetBoundClientRow()
  2475. {
  2476.     DBFETCHROWS FetchRows;
  2477.  
  2478.     if (m_pDataSource != NULL)
  2479.     {
  2480.         if(m_pRowset == NULL)
  2481.             return S_OK;
  2482.  
  2483.         if(m_pRowset->m_hRow == NULL)
  2484.             return S_OK;
  2485.  
  2486.         return m_pRowset->GetData();
  2487.     }
  2488.  
  2489.     if (m_nBindings == 0)
  2490.         return S_OK;
  2491.  
  2492.     FetchRows.pData = m_pValues;
  2493.     FetchRows.pVarData = NULL;
  2494.     FetchRows.cbVarData = NULL;
  2495.     FetchRows.cRowsRequested = 1;
  2496.     FetchRows.dwFlags = 0;
  2497.  
  2498.     LARGE_INTEGER dl = { 0, 0};
  2499.  
  2500.     return m_pCursorMove->Move(1, (LPVOID)&DBBMK_CURRENT, dl, &FetchRows);
  2501. }
  2502.  
  2503. COleVariant CDataSourceControl::ToVariant(int nCol)
  2504. {
  2505.     ASSERT(m_pDataSource != NULL);
  2506.     ASSERT(m_pDynamicAccessor != NULL);
  2507.     COleVariant vt;
  2508.     DBSTATUS dbStatus;
  2509.     DBTYPE dbType;
  2510.  
  2511.     m_pDynamicAccessor->GetStatus(nCol, &dbStatus);
  2512.     if(dbStatus == DBSTATUS_S_ISNULL)
  2513.         return vt;                      // just return a blank variant
  2514.  
  2515.     if(!m_pDynamicAccessor->GetColumnType(nCol, &dbType))
  2516.         return vt;
  2517.     switch (dbType)
  2518.     {
  2519.     case DBTYPE_VARIANT:
  2520.         vt = COleVariant((LPCVARIANT)m_pDynamicAccessor->GetValue(nCol));
  2521.         break;
  2522.     case DBTYPE_STR:
  2523.         vt = COleVariant(CString((LPCSTR)m_pDynamicAccessor->GetValue(nCol)), VT_BSTR);
  2524.         break;
  2525.     case DBTYPE_WSTR:
  2526.     case DBTYPE_BSTR:
  2527.         vt = COleVariant(CString((LPCWSTR)m_pDynamicAccessor->GetValue(nCol)), VT_BSTR);
  2528.         break;
  2529.     case DBTYPE_I1:
  2530.     case DBTYPE_UI1:
  2531.         vt = COleVariant(*((BYTE*)m_pDynamicAccessor->GetValue(nCol)));
  2532.         break;
  2533.     case DBTYPE_I2:
  2534.     case DBTYPE_UI2:
  2535.         vt = COleVariant(*((short*)m_pDynamicAccessor->GetValue(nCol)));
  2536.         break;
  2537.     case DBTYPE_I4:
  2538.     case DBTYPE_UI4:
  2539.         vt = COleVariant(*((long*)m_pDynamicAccessor->GetValue(nCol)));
  2540.         break;
  2541.     case DBTYPE_R4:
  2542.         vt = COleVariant(*((float*)m_pDynamicAccessor->GetValue(nCol)));
  2543.         break;
  2544.     case DBTYPE_R8:
  2545.         vt = COleVariant(*((double*)m_pDynamicAccessor->GetValue(nCol)));
  2546.         break;
  2547.     case DBTYPE_BOOL:
  2548.         vt = COleVariant((short)*(BOOL*)m_pDynamicAccessor->GetValue(nCol), VT_BOOL);
  2549.         break;
  2550.     case DBTYPE_DATE:
  2551.         {
  2552.             COleDateTime dt(*((DATE*)m_pDynamicAccessor->GetValue(nCol)));
  2553.             vt = COleVariant(dt);
  2554.         }
  2555.         break;
  2556.     case DBTYPE_CY:
  2557.         {
  2558.             COleCurrency cy(*((CURRENCY*)m_pDynamicAccessor->GetValue(nCol)));
  2559.             vt = COleVariant(cy);
  2560.         }
  2561.         break;
  2562.     case DBTYPE_NUMERIC:
  2563.         {
  2564.             DB_NUMERIC num;
  2565.  
  2566.             if(m_pDynamicAccessor->GetValue(nCol, &num))
  2567.             {
  2568.                 double dbl;
  2569.  
  2570.                 dbl = (double)*((__int64*)num.val);
  2571.                 while(num.scale-- > 0)
  2572.                     dbl /= 10;
  2573.                 if(num.sign == 0)
  2574.                     dbl = -dbl;
  2575.                 vt = COleVariant(dbl);
  2576.             }
  2577.         }
  2578.         break;
  2579.     case DBTYPE_DBDATE:
  2580.         {
  2581.             DBDATE dbDate;
  2582.  
  2583.             if(m_pDynamicAccessor->GetValue(nCol, &dbDate))
  2584.             {
  2585.                 COleDateTime dt;
  2586.  
  2587.                 dt.SetDate(dbDate.year, dbDate.month, dbDate.day);
  2588.                 vt = COleVariant(dt);
  2589.             }
  2590.         }
  2591.         break;
  2592.     case DBTYPE_DBTIME:
  2593.         {
  2594.             DBTIME dbTime;
  2595.  
  2596.             if(m_pDynamicAccessor->GetValue(nCol, &dbTime))
  2597.             {
  2598.                 COleDateTime dt;
  2599.  
  2600.                 dt.SetTime(dbTime.hour, dbTime.minute, dbTime.second);
  2601.                 vt = COleVariant(dt);
  2602.             }
  2603.         }
  2604.         break;
  2605.     case DBTYPE_DBTIMESTAMP:
  2606.         {
  2607.             DBTIMESTAMP dbTimeStamp;
  2608.  
  2609.             if(m_pDynamicAccessor->GetValue(nCol, &dbTimeStamp))
  2610.             {
  2611.                 vt = COleVariant(COleDateTime(dbTimeStamp.year, dbTimeStamp.month, dbTimeStamp.day,
  2612.                                               dbTimeStamp.hour, dbTimeStamp.minute, dbTimeStamp.second));
  2613.             }
  2614.         }
  2615.         break;
  2616.     case DBTYPE_NULL:
  2617.     case DBTYPE_EMPTY:
  2618.         break;
  2619.     default:
  2620.         TRACE2("Unsupported DBTYPE (%d) in column %d\n", dbType, nCol);
  2621.         break;
  2622.     }
  2623.     return vt;
  2624. }
  2625.  
  2626. HRESULT CDataSourceControl::UpdateControls()
  2627. {
  2628.     m_bUpdateInProgress = TRUE;
  2629.     int nItem = 0;
  2630.     for (int nCol=0; nCol<m_nColumns; nCol++)
  2631.     {
  2632.         POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
  2633.         while (pos)
  2634.         {
  2635.             COleControlSite* pSite = (COleControlSite *)
  2636.                 m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
  2637.  
  2638.             DISPPARAMS dispparamsSetProp;
  2639.             DISPID dispidNamed = DISPID_PROPERTYPUT;
  2640.             EXCEPINFO excepinfo;
  2641.             memset(&excepinfo, 0, sizeof(EXCEPINFO));
  2642.             UINT uArgErr;
  2643.             COleVariant vt;
  2644.             if (m_pDataSource != NULL)
  2645.             {
  2646.                 vt = ToVariant(nCol + 1);
  2647.                 dispparamsSetProp.rgvarg = &vt;
  2648.             }
  2649.             else
  2650.             {
  2651.                 dispparamsSetProp.rgvarg = &m_pValues[nItem];
  2652.             }
  2653.             dispparamsSetProp.rgdispidNamedArgs = &dispidNamed;
  2654.             dispparamsSetProp.cArgs = 1;
  2655.             dispparamsSetProp.cNamedArgs = 1;
  2656.             HRESULT hRes;
  2657.             LPDISPATCH pDispatch;
  2658.             pSite->m_bIgnoreNotify = TRUE;
  2659.             if (pSite->m_pObject == NULL)
  2660.                 continue;
  2661.             hRes = pSite->m_pObject->QueryInterface(IID_IDispatch, (LPVOID *) &pDispatch);
  2662.             if (FAILED(hRes))
  2663.                 continue;
  2664.             hRes = pDispatch->Invoke(pSite->m_defdispid, IID_NULL, 0, INVOKE_PROPERTYPUT, &dispparamsSetProp,
  2665.                 NULL, &excepinfo, &uArgErr);    //Set the bound control property
  2666.             pDispatch->Release();
  2667.             pSite->m_bIgnoreNotify = FALSE;
  2668.  
  2669.             if (excepinfo.bstrSource)
  2670.                 SysFreeString(excepinfo.bstrSource);
  2671.             if (excepinfo.bstrDescription)
  2672.                 SysFreeString(excepinfo.bstrDescription);
  2673.             if (excepinfo.bstrHelpFile)
  2674.                 SysFreeString(excepinfo.bstrHelpFile);
  2675.  
  2676.             vt.Clear();
  2677.             nItem++;
  2678.         }
  2679.     }
  2680.     m_bUpdateInProgress = FALSE;
  2681.     return S_OK;
  2682. }
  2683.  
  2684. HRESULT CDataSourceControl::UpdateCursor()
  2685. {
  2686.     HRESULT hRes;
  2687.     int nVariant = 0;
  2688.     int nDirtyField = 0;
  2689.  
  2690.     if (m_pDataSource != NULL)
  2691.     {
  2692.         if(m_pDynamicAccessor == NULL)
  2693.             return S_OK;
  2694.         // First go through all simple bound properties
  2695.         for (int nCol=1; nCol<=m_nColumns; nCol++)
  2696.         {
  2697.             POSITION pos = m_pMetaRowData[nCol - 1].m_pClientList->GetHeadPosition();
  2698.             while (pos)
  2699.             {
  2700.                 COleControlSite* pSite = (COleControlSite *)
  2701.                     m_pMetaRowData[nCol - 1].m_pClientList->GetNext(pos);
  2702.                 DBTYPE dbType;
  2703.  
  2704.                 if (pSite->m_bIsDirty)
  2705.                 {
  2706.                     pSite->m_bIsDirty = FALSE;
  2707.  
  2708.                     nDirtyField++;
  2709.                     if (nDirtyField == 1)
  2710.                     {
  2711.                         // UpdateinProgress semaphore - unexpected state
  2712.                         ASSERT(!m_bUpdateInProgress);
  2713.                         m_bUpdateInProgress = TRUE;
  2714.                     }
  2715.  
  2716.                     COleVariant var(pSite->m_varResult);
  2717.                     CManualAccessor accessor;
  2718.  
  2719.                     // Create accessor for output column
  2720.                     accessor.CreateAccessor(1, m_pDynamicAccessor->GetValue(nCol), m_pDynamicAccessor->m_pColumnInfo[nCol].ulColumnSize);
  2721.                     accessor.AddBindEntry(m_pDynamicAccessor->m_pColumnInfo[nCol].iOrdinal,
  2722.                                           m_pDynamicAccessor->m_pColumnInfo[nCol].wType,
  2723.                                           m_pDynamicAccessor->m_pColumnInfo[nCol].ulColumnSize,
  2724.                                           m_pDynamicAccessor->GetValue(nCol));
  2725.                     accessor.BindColumns(m_pRowset->m_spRowset);
  2726.  
  2727.                     VERIFY(m_pDynamicAccessor->GetColumnType(nCol, &dbType));
  2728.                     switch(dbType)
  2729.                     {
  2730.                     case DBTYPE_I2:
  2731.                         var.ChangeType(VT_I2);
  2732.                         m_pDynamicAccessor->SetValue(nCol, var.iVal);
  2733.                         break;
  2734.                     case DBTYPE_I4:
  2735.                         var.ChangeType(VT_I4);
  2736.                         m_pDynamicAccessor->SetValue(nCol, var.lVal);
  2737.                         break;
  2738.                     case DBTYPE_R4:
  2739.                         var.ChangeType(VT_R4);
  2740.                         m_pDynamicAccessor->SetValue(nCol, var.fltVal);
  2741.                         break;
  2742.                     case DBTYPE_R8:
  2743.                         var.ChangeType(VT_R8);
  2744.                         m_pDynamicAccessor->SetValue(nCol, var.dblVal);
  2745.                         break;
  2746.                     case DBTYPE_CY:
  2747.                         var.ChangeType(VT_CY);
  2748.                         *(CY*)m_pDynamicAccessor->GetValue(nCol) = var.cyVal;
  2749.                         break;
  2750.                     case DBTYPE_DATE:
  2751.                         var.ChangeType(VT_DATE);
  2752.                         m_pDynamicAccessor->SetValue(nCol, var.date);
  2753.                         break;
  2754.                     case DBTYPE_BSTR:
  2755.                     case DBTYPE_WSTR:
  2756.                         var.ChangeType(VT_BSTR);
  2757.                         wcsncpy((wchar_t*)m_pDynamicAccessor->GetValue(nCol), var.bstrVal, m_pDynamicAccessor->m_pColumnInfo[nCol].ulColumnSize);
  2758.                         break;
  2759.                     case DBTYPE_BOOL:
  2760.                         var.ChangeType(VT_BOOL);
  2761.                         m_pDynamicAccessor->SetValue(nCol, var.boolVal);
  2762.                         break;
  2763.                     case DBTYPE_DECIMAL:
  2764.                         var.ChangeType(VT_DECIMAL);
  2765.                         m_pDynamicAccessor->SetValue(nCol, var.decVal);
  2766.                         break;
  2767.                     case DBTYPE_UI1:
  2768.                         var.ChangeType(VT_UI1);
  2769.                         m_pDynamicAccessor->SetValue(nCol, var.bVal);
  2770.                         break;
  2771.                     case DBTYPE_I1:
  2772.                         var.ChangeType(VT_I1);
  2773.                         m_pDynamicAccessor->SetValue(nCol, (signed char)var.cVal);
  2774.                         break;
  2775.                     case DBTYPE_UI2:
  2776.                         var.ChangeType(VT_UI2);
  2777.                         m_pDynamicAccessor->SetValue(nCol, var.uiVal);
  2778.                         break;
  2779.                     case DBTYPE_UI4:
  2780.                         var.ChangeType(VT_UI4);
  2781.                         m_pDynamicAccessor->SetValue(nCol, var.ulVal);
  2782.                         break;
  2783.                     case DBTYPE_STR:
  2784.                         var.ChangeType(VT_BSTR);
  2785.                         WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, (char*)m_pDynamicAccessor->GetValue(nCol),
  2786.                                             m_pDynamicAccessor->m_pColumnInfo[nCol].ulColumnSize, NULL, NULL);
  2787.                         break;
  2788.                     case DBTYPE_DBTIMESTAMP:
  2789.                         DBTIMESTAMP ts;
  2790.                         SYSTEMTIME    sysTime;
  2791.                         var.ChangeType(VT_DATE);
  2792.                         memset(&ts, 0, sizeof(DBTIMESTAMP));
  2793.                         VariantTimeToSystemTime(var.date, &sysTime);
  2794.                         ts.year = sysTime.wYear;
  2795.                         ts.month = sysTime.wMonth;
  2796.                         ts.day = sysTime.wDay;
  2797.                         ts.hour = sysTime.wHour;
  2798.                         ts.minute = sysTime.wMinute;
  2799.                         ts.second = sysTime.wSecond;
  2800.                         ts.fraction = sysTime.wMilliseconds / 1000000;
  2801.                         m_pDynamicAccessor->SetValue(nCol, ts);
  2802.                         break;
  2803.                     default:
  2804.                         TRACE2("Unsupported DBTYPE (%d) in column %d\n", dbType, nCol);
  2805.                         break;
  2806.                     }
  2807.  
  2808.                     m_pRowset->SetAccessor(&accessor);
  2809.                     m_pRowset->SetData();
  2810.                     m_pRowset->SetAccessor(m_pDynamicAccessor);
  2811.  
  2812.                     ::VariantClear(&pSite->m_varResult);
  2813.                 }
  2814.                 nVariant++;
  2815.             }
  2816.         }
  2817.         if (nDirtyField > 0)
  2818.         {
  2819.             m_bUpdateInProgress = FALSE;
  2820.         }
  2821.         return S_OK;
  2822.     }
  2823.     // Do we have an updateable cursor?
  2824.     if (m_pCursorUpdateARow == NULL)
  2825.     {
  2826.         // If not attempt to get one
  2827.         hRes = m_pCursorMove->QueryInterface(IID_ICursorUpdateARow,
  2828.             (LPVOID *)&m_pCursorUpdateARow);
  2829.  
  2830.         if (FAILED(hRes))
  2831.             return S_OK; // no update cursor, so forget updating
  2832.     }
  2833.  
  2834.     // First go through all simple bound properties
  2835.     for (int nCol=0; nCol<m_nColumns; nCol++)
  2836.     {
  2837.         POSITION pos = m_pMetaRowData[nCol].m_pClientList->GetHeadPosition();
  2838.         while (pos)
  2839.         {
  2840.             COleControlSite* pSite = (COleControlSite *)
  2841.                 m_pMetaRowData[nCol].m_pClientList->GetNext(pos);
  2842.  
  2843.             if (pSite->m_bIsDirty)
  2844.             {
  2845.                 pSite->m_bIsDirty = FALSE;
  2846.  
  2847.                 nDirtyField++;
  2848.                 if (nDirtyField == 1)
  2849.                 {
  2850.                     DWORD dwEdit;
  2851.                     hRes = m_pCursorUpdateARow->GetEditMode(&dwEdit);
  2852.                     if (FAILED(hRes))
  2853.                         return hRes;
  2854.                     if (dwEdit == DBEDITMODE_NONE)
  2855.                     {
  2856.                         hRes = m_pCursorUpdateARow->BeginUpdate(DBROWACTION_UPDATE);
  2857.                         if (FAILED(hRes))
  2858.                             return hRes;
  2859.                     }
  2860.                     // UpdateinProgress semaphore - unexpected state
  2861.                     ASSERT(!m_bUpdateInProgress);
  2862.                     m_bUpdateInProgress = TRUE;
  2863.                 }
  2864.                 DBBINDPARAMS bpBindParams;
  2865.                 DWORD dwIndicator = sizeof(VARIANT);
  2866.                 COleVariant vt;
  2867.                 switch (V_VT(&pSite->m_varResult))
  2868.                 {
  2869.                 case VT_EMPTY:
  2870.                 case VT_NULL:
  2871.                 case VT_ERROR:
  2872.                     dwIndicator = DB_NULL;
  2873.                     vt = pSite->m_varResult;
  2874.                     break;
  2875.                 case VT_BSTR:
  2876.                     if(*pSite->m_varResult.bstrVal == 0)
  2877.                     {
  2878.                         dwIndicator = DB_NULL;
  2879.                         break;
  2880.                     }
  2881.                 default:
  2882.                     vt = pSite->m_varResult;
  2883.                     break;
  2884.                 }
  2885.                 bpBindParams.cbMaxLen     = 0L;
  2886.                 bpBindParams.dwBinding    = DBBINDING_VARIANT;
  2887.                 bpBindParams.dwDataType   = m_pColumnBindings[nVariant].dwDataType;
  2888.                 bpBindParams.cbVarDataLen = 0L;
  2889.                 bpBindParams.dwInfo       = dwIndicator;
  2890.                 bpBindParams.pData        = &vt;
  2891.  
  2892.                 hRes = m_pCursorUpdateARow->SetColumn(&m_pColumnBindings[nVariant].columnID, &bpBindParams);
  2893.  
  2894.                 ::VariantClear(&pSite->m_varResult);
  2895.             }
  2896.             nVariant++;
  2897.         }
  2898.     }
  2899.     // Now go through all cursor bound properties
  2900.     POSITION pos = m_CursorBoundProps.GetHeadPosition();
  2901.     while (pos != NULL)
  2902.     {
  2903.         CDataBoundProperty* pProp = (CDataBoundProperty*) m_CursorBoundProps.GetNext(pos);
  2904.         if (pProp->m_pClientSite->m_pObject == NULL)
  2905.             continue;
  2906.         IBoundObject *pBO;
  2907.         if (SUCCEEDED(pProp->m_pClientSite->m_pObject->QueryInterface(IID_IBoundObject,
  2908.             (LPVOID *) &pBO)))
  2909.         {
  2910.             if (pBO->IsDirty(pProp->m_dispid) == S_OK)
  2911.             {
  2912.                 nDirtyField++;
  2913.                 if (nDirtyField == 1)
  2914.                 {
  2915.                     DWORD dwEdit;
  2916.                     hRes = m_pCursorUpdateARow->GetEditMode(&dwEdit);
  2917.                     if (FAILED(hRes))
  2918.                         return hRes;
  2919.                     if (dwEdit == DBEDITMODE_NONE)
  2920.                     {
  2921.                         hRes = m_pCursorUpdateARow->BeginUpdate(DBROWACTION_UPDATE);
  2922.                         if (FAILED(hRes))
  2923.                             return hRes;
  2924.                     }
  2925.                     // UpdateinProgress semaphore - unexpected state
  2926.                     ASSERT(!m_bUpdateInProgress);
  2927.                     m_bUpdateInProgress = TRUE;
  2928.                 }
  2929.             }
  2930.             pBO->Release();
  2931.         }
  2932.     }
  2933.  
  2934.     if (nDirtyField > 0)
  2935.     {
  2936.         hRes = m_pCursorUpdateARow->Update(0,0,0);
  2937.         m_bUpdateInProgress = FALSE;
  2938.         if (FAILED(hRes))
  2939.         {
  2940.             // Update failed w/dirty controls
  2941.             ASSERT(hRes!= S_OK);
  2942.             UpdateControls();
  2943.             return hRes;
  2944.         }
  2945.     }
  2946.  
  2947.     return S_OK;
  2948. }
  2949.  
  2950.  
  2951. /////////////////////////////////////////////////////////////////////////////
  2952. // CDataBoundProperty Handles Databound Controls
  2953.  
  2954. CDataBoundProperty::CDataBoundProperty(CDataBoundProperty* pLast, DISPID dispid, WORD ctlid) :
  2955.     m_dispid(dispid),
  2956.     m_ctlid(ctlid),
  2957.     m_pClientSite(NULL),
  2958.     m_pDSCSite(NULL),
  2959.     m_bIsDirty(FALSE),
  2960.     m_pNext(pLast)
  2961. {
  2962. }
  2963.  
  2964. void CDataBoundProperty::SetClientSite(COleControlSite *pClientSite)
  2965. {
  2966.     m_pClientSite = pClientSite;
  2967. }
  2968.  
  2969.  
  2970. // (Re)bind a cursor bound property to a DSC
  2971. void CDataBoundProperty::SetDSCSite(COleControlSite *pDSCSite)
  2972. {
  2973.     if (m_pDSCSite == pDSCSite)
  2974.         return;
  2975.     m_pDSCSite = pDSCSite;
  2976.     Notify();
  2977. }
  2978.  
  2979. CDataBoundProperty* CDataBoundProperty::GetNext()
  2980. {
  2981.     return m_pNext;
  2982. }
  2983.  
  2984. void CDataBoundProperty::RemoveSource()
  2985. {
  2986.     m_pDSCSite = NULL;
  2987.     Notify();
  2988. }
  2989.  
  2990. void CDataBoundProperty::Notify()
  2991. {
  2992.     if (m_dispid != DISPID_DATASOURCE)
  2993.     {
  2994.         IBoundObject *pBO;
  2995.         if (m_pClientSite != NULL)
  2996.         {
  2997.             if (SUCCEEDED(m_pClientSite->m_pObject->QueryInterface(IID_IBoundObject,
  2998.                 (LPVOID *) &pBO)))
  2999.             {
  3000.                 pBO->OnSourceChanged(m_dispid, m_pDSCSite != NULL, &m_bOwnXferOut);
  3001.                 pBO->Release();
  3002.             }
  3003.             else
  3004.             {
  3005.                 IUnknown* pUnk = GetCursor();
  3006.                 if (pUnk != NULL)
  3007.                 {
  3008.                     VARTYPE vt = VT_UNKNOWN;
  3009.                     if (m_pDSCSite->m_pDataSourceControl != NULL)
  3010.                         vt |= VT_MFCFORCEPUTREF;
  3011.                     m_pClientSite->SetProperty(m_dispid, vt, pUnk);
  3012.                 }
  3013.             }
  3014.         }
  3015.     }
  3016. }
  3017.  
  3018. IUnknown* CDataBoundProperty::GetCursor()
  3019. {
  3020.     if(m_pDSCSite == NULL)
  3021.         return NULL;
  3022.  
  3023.     m_pDSCSite->EnableDSC();
  3024.  
  3025.     ASSERT(m_pDSCSite->m_pDataSourceControl);
  3026.  
  3027.     m_pDSCSite->m_pDataSourceControl->BindProp(this);
  3028.  
  3029.     return m_pDSCSite->m_pDataSourceControl->GetCursor();
  3030. }
  3031.  
  3032. /////////////////////////////////////////////////////////////////////////////
  3033. // COleControlSite::XBoundObjectSite
  3034.  
  3035. HRESULT COleControlSite::GetCursor(
  3036.     DISPID dispid, LPUNKNOWN* ppcursorOut, LPVOID *ppcidOut)
  3037. {
  3038.     if (ppcidOut != NULL)
  3039.         *ppcidOut = NULL;
  3040.  
  3041.     CDataBoundProperty* pBinding = m_pBindings;
  3042.     while (pBinding != NULL)
  3043.     {
  3044.         if (pBinding->m_dispid == dispid)
  3045.         {
  3046.             *ppcursorOut = pBinding->GetCursor();
  3047.             return S_OK;
  3048.         }
  3049.         pBinding = pBinding->GetNext();
  3050.     }
  3051.     return S_OK;
  3052. }
  3053.  
  3054. STDMETHODIMP_(ULONG) COleControlSite::XBoundObjectSite::AddRef()
  3055. {
  3056.     METHOD_PROLOGUE_EX(COleControlSite, BoundObjectSite)
  3057.     return (ULONG)pThis->ExternalAddRef();
  3058. }
  3059.  
  3060. STDMETHODIMP_(ULONG) COleControlSite::XBoundObjectSite::Release()
  3061. {
  3062.     METHOD_PROLOGUE_EX(COleControlSite, BoundObjectSite)
  3063.     return (ULONG)pThis->ExternalRelease();
  3064. }
  3065.  
  3066. STDMETHODIMP COleControlSite::XBoundObjectSite::QueryInterface(
  3067.     REFIID iid, LPVOID far * ppvObj)
  3068. {
  3069.     METHOD_PROLOGUE_EX(COleControlSite, BoundObjectSite)
  3070.     return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
  3071. }
  3072.  
  3073. STDMETHODIMP COleControlSite::XBoundObjectSite::GetCursor(
  3074.     DISPID dispid, LPLPCURSOR ppcursorOut, LPVOID *ppcidOut)
  3075. {
  3076.     METHOD_PROLOGUE_EX(COleControlSite, BoundObjectSite)
  3077.     return pThis->GetCursor(dispid, (LPUNKNOWN*)ppcursorOut, ppcidOut);
  3078. }
  3079.  
  3080.  
  3081. /////////////////////////////////////////////////////////////////////////////
  3082. // COleControlSite::XNotifyDBEvents
  3083.  
  3084. STDMETHODIMP_(ULONG) COleControlSite::XNotifyDBEvents::AddRef()
  3085. {
  3086.     return 1;
  3087. }
  3088.  
  3089. STDMETHODIMP_(ULONG) COleControlSite::XNotifyDBEvents::Release()
  3090. {
  3091.     return 0;
  3092. }
  3093.  
  3094. STDMETHODIMP COleControlSite::XNotifyDBEvents::QueryInterface(
  3095.     REFIID iid, LPVOID far * ppvObj)
  3096. {
  3097.     METHOD_PROLOGUE_EX_(COleControlSite, NotifyDBEvents)
  3098.  
  3099.     if (IsEqualIID(iid, IID_IUnknown) ||
  3100.         IsEqualIID(iid, IID_INotifyDBEvents))
  3101.     {
  3102.         *ppvObj = this;
  3103.         AddRef();
  3104.         return S_OK;
  3105.     }
  3106.     else
  3107.     {
  3108.         return E_NOINTERFACE;
  3109.     }
  3110. }
  3111.  
  3112. STDMETHODIMP COleControlSite::XNotifyDBEvents::OKToDo(
  3113.     DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
  3114. {
  3115.     METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
  3116.  
  3117.     HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
  3118.         dscOKToDo);
  3119.     if (FAILED(hRes))
  3120.         return hRes;
  3121.  
  3122.     DWORD reason = rgReasons[0].dwReason;
  3123.  
  3124.     if (reason == DBREASON_SETCOLUMN ||
  3125.         reason == DBREASON_INSERTED ||
  3126.         reason == DBREASON_MODIFIED)
  3127.         return S_OK;
  3128.  
  3129.     // Mask out all notifications except as currency changes and update
  3130.     if (!(dwEventWhat & DBEVENT_CURRENT_ROW_CHANGED) &&
  3131.         reason != DBREASON_INSERTED &&
  3132.         reason != DBREASON_MODIFIED &&
  3133.         reason != DBREASON_DELETED &&
  3134.         reason != DBREASON_ADDNEW)
  3135.         return S_OK;
  3136.  
  3137.     CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
  3138.     if (pDSC == NULL)
  3139.         return S_OK;
  3140.  
  3141.     if (!(dwEventWhat & DBEVENT_CURRENT_ROW_CHANGED))
  3142.         return S_OK;
  3143.  
  3144.     return pDSC->UpdateCursor();
  3145. }
  3146.  
  3147. STDMETHODIMP COleControlSite::XNotifyDBEvents::Cancelled(
  3148.     DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
  3149. {
  3150.     METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
  3151.  
  3152.     HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
  3153.         dscCancelled);
  3154.     if (FAILED(hRes))
  3155.         return hRes;
  3156.  
  3157.     return S_OK;
  3158. }
  3159.  
  3160. STDMETHODIMP COleControlSite::XNotifyDBEvents::SyncBefore(
  3161.     DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
  3162. {
  3163.     METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
  3164.  
  3165.     HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
  3166.         dscSyncBefore);
  3167.     if (FAILED(hRes))
  3168.         return hRes;
  3169.  
  3170.     DWORD reason = rgReasons[0].dwReason;
  3171.  
  3172.     // Mask out all notifications except as shown
  3173.     if (reason != DBREASON_INSERTED &&
  3174.         reason != DBREASON_MODIFIED &&
  3175.         reason != DBREASON_ADDNEW)
  3176.         return S_OK;
  3177.  
  3178.     CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
  3179.     if (pDSC == NULL)
  3180.         return S_OK;
  3181.  
  3182.     if (dwEventWhat & DBEVENT_METADATA_CHANGED)
  3183.     {
  3184.         pDSC->UpdateCursor();
  3185.     }
  3186.  
  3187.     return S_OK;
  3188. }
  3189.  
  3190. STDMETHODIMP COleControlSite::XNotifyDBEvents::AboutToDo(
  3191.     DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
  3192. {
  3193.     METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
  3194.  
  3195.     HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
  3196.         dscAboutToDo);
  3197.     if (FAILED(hRes))
  3198.         return hRes;
  3199.  
  3200.     return S_OK;
  3201. }
  3202.  
  3203. STDMETHODIMP COleControlSite::XNotifyDBEvents::FailedToDo(
  3204.     DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
  3205. {
  3206.     METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
  3207.  
  3208.     HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
  3209.         dscFailedToDo);
  3210.     if (FAILED(hRes))
  3211.         return hRes;
  3212.  
  3213.     return S_OK;
  3214. }
  3215.  
  3216. STDMETHODIMP COleControlSite::XNotifyDBEvents::SyncAfter(
  3217.     DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
  3218. {
  3219.     METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
  3220.  
  3221.     HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
  3222.         dscSyncAfter);
  3223.     if (FAILED(hRes))
  3224.         return hRes;
  3225.  
  3226.     DWORD reason = rgReasons[0].dwReason;
  3227.  
  3228.     CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
  3229.     if (pDSC == NULL)
  3230.         return S_OK;
  3231.  
  3232.     //Check semaphore - don't want to collect data during Update if it was due to a Move (it's a NOP!)
  3233.     if (pDSC->m_bUpdateInProgress ||
  3234.         reason == DBREASON_EDIT ||
  3235.         reason == DBREASON_SETCOLUMN)
  3236.         return S_OK;
  3237.  
  3238.     //Mask out all notifications except as shown
  3239.     if (!(dwEventWhat & (DBEVENT_CURRENT_ROW_CHANGED | DBEVENT_CURRENT_ROW_DATA_CHANGED)))
  3240.         return S_OK;
  3241.  
  3242.     if (reason != DBREASON_INSERTED &&
  3243.         reason != DBREASON_MODIFIED)
  3244.     {
  3245.         BOOL bUpdateInProgress = pDSC->m_bUpdateInProgress;
  3246.         pDSC->m_bUpdateInProgress = TRUE;
  3247.         pDSC->GetBoundClientRow();
  3248.         pDSC->m_bUpdateInProgress = bUpdateInProgress;
  3249.         pDSC->UpdateControls();
  3250.     }
  3251.  
  3252.     return S_OK;
  3253. }
  3254.  
  3255. STDMETHODIMP COleControlSite::XNotifyDBEvents::DidEvent(
  3256.     DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[])
  3257. {
  3258.     METHOD_PROLOGUE_EX(COleControlSite, NotifyDBEvents)
  3259.  
  3260.     HRESULT hRes = FireEvent(dwEventWhat, cReasons, rgReasons,
  3261.         dscDidEvent);
  3262.     if (FAILED(hRes))
  3263.         return hRes;
  3264.  
  3265.     CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
  3266.     if (pDSC == NULL)
  3267.         return S_OK;
  3268.  
  3269.     if (dwEventWhat & DBEVENT_METADATA_CHANGED)
  3270.     {
  3271.         BOOL bUpdateInProgress = pDSC->m_bUpdateInProgress;
  3272.         pDSC->m_bUpdateInProgress = TRUE;
  3273.         pDSC->GetBoundClientRow();
  3274.         pDSC->m_bUpdateInProgress = bUpdateInProgress;
  3275.         pDSC->UpdateControls();
  3276.     }
  3277.  
  3278.     return S_OK;
  3279. }
  3280.  
  3281.  
  3282. HRESULT COleControlSite::XNotifyDBEvents::FireEvent(
  3283.     DWORD dwEventWhat, ULONG cReasons, DBNOTIFYREASON rgReasons[], DSCSTATE nState)
  3284. {
  3285.     METHOD_PROLOGUE_EX_(COleControlSite, NotifyDBEvents)
  3286.  
  3287.     if (dwEventWhat & DBEVENT_CURRENT_ROW_CHANGED
  3288.         || dwEventWhat & DBEVENT_CURRENT_ROW_DATA_CHANGED)
  3289.     {
  3290.         for (UINT i=0; i<cReasons; i++)
  3291.         {
  3292.             DSCREASON nReason = dscNoReason;
  3293.             switch (rgReasons[i].dwReason)
  3294.             {
  3295.             case DBREASON_CLOSE:
  3296.                 nReason = dscClose;
  3297.                 break;
  3298.             case DBREASON_FIND:
  3299.             case DBREASON_MOVE:
  3300.             case DBREASON_MOVEPERCENT:
  3301.             case DBREASON_NEWINDEX:
  3302.             case DBREASON_NEWPARAMETERS:
  3303.             case DBREASON_QUERYSPECCHANGED:
  3304.             case DBREASON_REFRESH:
  3305.             case DBREASON_SEEK:
  3306.             case DBREASON_SETRANGECHANGED:
  3307.                 nReason = dscMove;
  3308.                 break;
  3309.             case DBREASON_ADDNEW:
  3310.             case DBREASON_INSERTED:
  3311.                 nReason = dscInsert;
  3312.                 break;
  3313.             case DBREASON_EDIT:
  3314.                 nReason = dscEdit;
  3315.                 break;
  3316.             case DBREASON_MODIFIED:
  3317.             case DBREASON_RECALC:
  3318.             case DBREASON_ROLLBACK:
  3319.             case DBREASON_ROWFIXUP:
  3320.                 nReason = dscModify;
  3321.                 break;
  3322.             case DBREASON_DELETED:
  3323.                 nReason = dscDelete;
  3324.                 break;
  3325.             case DBREASON_COMMIT:
  3326.                 nReason = dscCommit;
  3327.                 break;
  3328.             }
  3329.             if (nReason != dscNoReason)
  3330.             {
  3331.                 AFX_EVENT event(AFX_EVENT::propDSCNotify);
  3332.                 event.m_nDSCState = nState;
  3333.                 event.m_nDSCReason = nReason;
  3334.                 pThis->OnEvent(&event);
  3335.                 return event.m_hResult;
  3336.             }
  3337.         }
  3338.         return S_OK;
  3339.     }
  3340.     return S_OK;
  3341. }
  3342.  
  3343. STDMETHODIMP_(ULONG) COleControlSite::XRowsetNotify::AddRef()
  3344. {
  3345.     return 1;
  3346. }
  3347.  
  3348. STDMETHODIMP_(ULONG) COleControlSite::XRowsetNotify::Release()
  3349. {
  3350.     return 0;
  3351. }
  3352.  
  3353. STDMETHODIMP COleControlSite::XRowsetNotify::QueryInterface(
  3354.     REFIID iid, LPVOID far * ppvObj)
  3355. {
  3356.     METHOD_PROLOGUE_EX_(COleControlSite, RowsetNotify)
  3357.  
  3358.     if (IsEqualIID(iid, IID_IUnknown) ||
  3359.         IsEqualIID(iid, IID_IRowsetNotify))
  3360.     {
  3361.         *ppvObj = this;
  3362.         AddRef();
  3363.         return S_OK;
  3364.     }
  3365.     return E_NOINTERFACE;
  3366. }
  3367.  
  3368. STDMETHODIMP COleControlSite::XRowsetNotify::OnFieldChange(
  3369.     IRowset* /*pRowset*/, HROW /*hRow*/, ULONG /*cColumns*/, ULONG /*rgColumns*/[],
  3370.     DBREASON /*eReason*/, DBEVENTPHASE ePhase, BOOL /*fCantDeny*/)
  3371. {
  3372.     METHOD_PROLOGUE_EX(COleControlSite, RowsetNotify)
  3373.  
  3374.     DSCSTATE nState = dscNoState;
  3375.     switch(ePhase)
  3376.     {
  3377.     case DBEVENTPHASE_OKTODO:
  3378.         nState = dscOKToDo;
  3379.         break;
  3380.     case DBEVENTPHASE_ABOUTTODO:
  3381.         nState = dscAboutToDo;
  3382.         break;
  3383.     case DBEVENTPHASE_SYNCHAFTER:
  3384.         nState = dscSyncAfter;
  3385.         break;
  3386.     case DBEVENTPHASE_FAILEDTODO:
  3387.         nState = dscFailedToDo;
  3388.         break;
  3389.     case DBEVENTPHASE_DIDEVENT:
  3390.         nState = dscDidEvent;
  3391.         break;
  3392.     }
  3393.     if(nState == dscDidEvent)
  3394.     {
  3395.         CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
  3396.         if (pDSC == NULL)
  3397.             return S_OK;
  3398.  
  3399.         if(pDSC->m_bUpdateInProgress == FALSE)
  3400.         {
  3401.             ASSERT(pDSC->m_pRowset);
  3402.  
  3403.             BOOL bUpdateInProgress = pDSC->m_bUpdateInProgress;
  3404.             pDSC->m_bUpdateInProgress = TRUE;
  3405.             pDSC->GetBoundClientRow();
  3406.             pDSC->m_bUpdateInProgress = bUpdateInProgress;
  3407.             pDSC->UpdateControls();
  3408.         }
  3409.     }
  3410.  
  3411.     AFX_EVENT event(AFX_EVENT::propDSCNotify);
  3412.     event.m_nDSCState = nState;
  3413.     event.m_nDSCReason = dscModify;
  3414.     pThis->OnEvent(&event);
  3415.     return event.m_hResult;
  3416. }
  3417.  
  3418. STDMETHODIMP COleControlSite::XRowsetNotify::OnRowChange(
  3419.     IRowset* /*pRowset*/, ULONG cRows, const HROW rghRows[],
  3420.     DBREASON eReason, DBEVENTPHASE ePhase, BOOL /*fCantDeny*/)
  3421. {
  3422.     METHOD_PROLOGUE_EX(COleControlSite, RowsetNotify)
  3423.  
  3424.     HRESULT hRes = S_OK;
  3425.  
  3426.     DSCSTATE nState = dscNoState;
  3427.     switch(ePhase)
  3428.     {
  3429.     case DBEVENTPHASE_OKTODO:
  3430.         nState = dscOKToDo;
  3431.         break;
  3432.     case DBEVENTPHASE_ABOUTTODO:
  3433.         nState = dscAboutToDo;
  3434.         break;
  3435.     case DBEVENTPHASE_SYNCHAFTER:
  3436.         nState = dscSyncAfter;
  3437.         break;
  3438.     case DBEVENTPHASE_FAILEDTODO:
  3439.         nState = dscFailedToDo;
  3440.         break;
  3441.     case DBEVENTPHASE_DIDEVENT:
  3442.         nState = dscDidEvent;
  3443.         break;
  3444.     }
  3445.     DSCREASON nReason = dscNoReason;
  3446.     switch(eReason)
  3447.     {
  3448.     case DBREASON_ROW_ACTIVATE:
  3449.         nReason = dscMove;
  3450.         break;
  3451.     case DBREASON_ROW_DELETE:
  3452.         nReason = dscDelete;
  3453.         break;
  3454.     case DBREASON_ROW_INSERT:
  3455.         nReason = dscInsert;
  3456.         break;
  3457.     case DBREASON_ROW_UPDATE:
  3458.         nReason = dscCommit;
  3459.         break;
  3460.     }
  3461.     CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
  3462.     if (pDSC == NULL)
  3463.         return S_OK;
  3464.  
  3465.     ASSERT(pDSC->m_pRowset);
  3466.  
  3467.     if (nReason == dscCommit && nState == dscAboutToDo)
  3468.     {
  3469.         pDSC->UpdateCursor();
  3470.     }
  3471.     else if ((nReason == dscMove && cRows == 1) || (nState == dscSyncAfter && nReason == dscInsert))
  3472.     {
  3473.         pDSC->UpdateCursor();
  3474.         pDSC->m_pRowset->m_hRow = rghRows[0];
  3475.  
  3476.         BOOL bUpdateInProgress = pDSC->m_bUpdateInProgress;
  3477.         pDSC->m_bUpdateInProgress = TRUE;
  3478.         pDSC->GetBoundClientRow();
  3479.         pDSC->m_bUpdateInProgress = bUpdateInProgress;
  3480.         if(!pDSC->m_bUpdateInProgress)
  3481.             pDSC->UpdateControls();
  3482.     }
  3483.     if (nReason != dscNoReason)
  3484.     {
  3485.         AFX_EVENT event(AFX_EVENT::propDSCNotify);
  3486.         event.m_nDSCState = nState;
  3487.         event.m_nDSCReason = nReason;
  3488.         pThis->OnEvent(&event);
  3489.         hRes = event.m_hResult;
  3490.         if(FAILED(hRes))
  3491.             return hRes;
  3492.     }
  3493.     return S_OK;
  3494. }
  3495.  
  3496. STDMETHODIMP COleControlSite::XRowsetNotify::OnRowsetChange(
  3497.     IRowset* /*pRowset*/, DBREASON eReason, DBEVENTPHASE /*ePhase*/, BOOL /*fCantDeny*/)
  3498. {
  3499.     METHOD_PROLOGUE_EX(COleControlSite, RowsetNotify)
  3500.  
  3501.     if(eReason == DBREASON_ROWSET_CHANGED)
  3502.     {
  3503.         CDataSourceControl* pDSC = pThis->m_pDataSourceControl;
  3504.         if (pDSC == NULL)
  3505.             return S_OK;
  3506.  
  3507.         ASSERT(pDSC->m_pRowset);
  3508.         ASSERT(pDSC->m_pDynamicAccessor);
  3509.  
  3510.         pDSC->m_pDynamicAccessor->ReleaseAccessors(pDSC->m_pRowset->m_spRowset);
  3511.         pDSC->m_pDynamicAccessor->Close();
  3512.         pDSC->m_pDynamicAccessor->BindColumns(pDSC->m_pRowset->m_spRowset);
  3513.         if( pDSC->m_nColumns != (int)pDSC->m_pDynamicAccessor->GetColumnCount() )
  3514.         {
  3515.             pDSC->m_nColumns = pDSC->m_pDynamicAccessor->GetColumnCount();
  3516.             ::CoTaskMemFree(pDSC->m_pMetaRowData);
  3517.             pDSC->m_pMetaRowData = (CDataSourceControl::METAROWTYPE*)::CoTaskMemAlloc(sizeof(CDataSourceControl::METAROWTYPE) * pDSC->m_nColumns);
  3518.             ASSERT(pDSC->m_pMetaRowData);
  3519.             memset(pDSC->m_pMetaRowData, 0, sizeof(CDataSourceControl::METAROWTYPE) * pDSC->m_nColumns);
  3520.         }
  3521.     }
  3522.  
  3523.     return S_OK;
  3524. }
  3525.