home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OCCSITE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-02  |  70.1 KB  |  2,862 lines

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