home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLEDROP2.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  14.5 KB  |  549 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.  
  13. #ifdef AFX_OLE4_SEG
  14. #pragma code_seg(AFX_OLE4_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // COleDropTarget implementation
  26.  
  27. AFX_DATADEF int COleDropTarget::nScrollInset;
  28. AFX_DATADEF UINT COleDropTarget::nScrollDelay;
  29. AFX_DATADEF UINT COleDropTarget::nScrollInterval;
  30.  
  31. COleDropTarget::COleDropTarget()
  32. {
  33.     // initialize local state
  34.     m_hWnd = NULL;
  35.     m_lpDataObject = NULL;
  36.     m_nTimerID = MAKEWORD(-1, -1);
  37.  
  38.     AfxLockGlobals(CRIT_DROPTARGET);
  39.     static BOOL bInitialized;
  40.     if (!bInitialized)
  41.     {
  42. #ifndef _MAC
  43.         // get scroll metrics from win.ini
  44.         static const TCHAR szWindows[] = _T("windows");
  45.         static const TCHAR szScrollDelay[] = _T("DragScrollDelay");
  46.         static const TCHAR szScrollInset[] = _T("DragScrollInset");
  47.         static const TCHAR szScrollInterval[] = _T("DragScrollInterval");
  48.  
  49.         nScrollInset = GetProfileInt(szWindows, szScrollInset, DD_DEFSCROLLINSET);
  50.         nScrollDelay = GetProfileInt(szWindows, szScrollDelay, DD_DEFSCROLLDELAY);
  51.         nScrollInterval = GetProfileInt(szWindows, szScrollInterval,
  52.             DD_DEFSCROLLINTERVAL);
  53. #else
  54.         nScrollInset = DD_DEFSCROLLINSET;
  55.         nScrollDelay = DD_DEFSCROLLDELAY;
  56.         nScrollInterval = DD_DEFSCROLLINTERVAL;
  57. #endif
  58.         // now initialized, no need to call Initialize any more
  59.         bInitialized = TRUE;
  60.     }
  61.     AfxUnlockGlobals(CRIT_DROPTARGET);
  62.  
  63.     ASSERT_VALID(this);
  64. }
  65.  
  66. COleDropTarget::~COleDropTarget()
  67. {
  68.     ASSERT_VALID(this);
  69.  
  70.     if (m_hWnd != NULL)
  71.     {
  72.         TRACE0("COleDropTarget::Revoke not called before destructor --\n");
  73.         TRACE0("\tmay cause RIPs under debug Windows.\n");
  74.         Revoke();
  75.     }
  76. }
  77.  
  78. BOOL COleDropTarget::Register(CWnd* pWnd)
  79. {
  80.     ASSERT_VALID(this);
  81.     ASSERT(m_hWnd == NULL);     // registering drop target twice?
  82.     ASSERT_VALID(pWnd);
  83.  
  84.     LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
  85.     ASSERT(lpUnknown != NULL);
  86.  
  87.     // the object must be locked externally to keep LRPC connections alive
  88.     if (CoLockObjectExternal(lpUnknown, TRUE, FALSE) != S_OK)
  89.         return FALSE;
  90.  
  91.     // connect the HWND to the IDropTarget implementation
  92.     if (RegisterDragDrop(pWnd->m_hWnd,
  93.         (LPDROPTARGET)GetInterface(&IID_IDropTarget)) != S_OK)
  94.     {
  95.         CoLockObjectExternal(lpUnknown, FALSE, FALSE);
  96.         return FALSE;
  97.     }
  98.  
  99.     // connect internal data
  100.     m_hWnd = pWnd->m_hWnd;
  101.     ASSERT(pWnd->m_pDropTarget == NULL);
  102.     pWnd->m_pDropTarget = this;
  103.  
  104.     return TRUE;
  105. }
  106.  
  107. void COleDropTarget::Revoke()
  108. {
  109.     ASSERT_VALID(this);
  110.     ASSERT(m_lpDataObject == NULL);
  111.  
  112.     if (m_hWnd == NULL)
  113.     {
  114.         ASSERT(m_nTimerID == MAKEWORD(-1, -1));
  115.         return;
  116.     }
  117.  
  118.     // disconnect from OLE
  119.     RevokeDragDrop(m_hWnd);
  120.     CoLockObjectExternal((LPUNKNOWN)GetInterface(&IID_IUnknown), FALSE, TRUE);
  121.  
  122.     // disconnect internal data
  123.     CWnd::FromHandle(m_hWnd)->m_pDropTarget = NULL;
  124.     m_hWnd = NULL;
  125. }
  126.  
  127. /////////////////////////////////////////////////////////////////////////////
  128. // default implementation of drag/drop scrolling
  129.  
  130. DROPEFFECT COleDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState,
  131.     CPoint point)
  132. {
  133.     ASSERT_VALID(this);
  134.     ASSERT_VALID(pWnd);
  135.  
  136.     // CWnds are allowed, but don't support autoscrolling
  137.     if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  138.         return DROPEFFECT_NONE;
  139.     CView* pView = (CView*)pWnd;
  140.     DROPEFFECT dropEffect = pView->OnDragScroll(dwKeyState, point);
  141.  
  142.     // DROPEFFECT_SCROLL means do the default
  143.     if (dropEffect != DROPEFFECT_SCROLL)
  144.         return dropEffect;
  145.  
  146.     // get client rectangle of destination window
  147.     CRect rectClient;
  148.     pWnd->GetClientRect(&rectClient);
  149.     CRect rect = rectClient;
  150.  
  151.     // hit-test against inset region
  152.     UINT nTimerID = MAKEWORD(-1, -1);
  153.     rect.InflateRect(-nScrollInset, -nScrollInset);
  154.     CSplitterWnd* pSplitter = NULL;
  155.     if (rectClient.PtInRect(point) && !rect.PtInRect(point))
  156.     {
  157.         // determine which way to scroll along both X & Y axis
  158.         if (point.x < rect.left)
  159.             nTimerID = MAKEWORD(SB_LINEUP, HIBYTE(nTimerID));
  160.         else if (point.x >= rect.right)
  161.             nTimerID = MAKEWORD(SB_LINEDOWN, HIBYTE(nTimerID));
  162.         if (point.y < rect.top)
  163.             nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEUP);
  164.         else if (point.y >= rect.bottom)
  165.             nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEDOWN);
  166.         ASSERT(nTimerID != MAKEWORD(-1, -1));
  167.  
  168.         // check for valid scroll first
  169.         pSplitter = CView::GetParentSplitter(pView, FALSE);
  170.         BOOL bEnableScroll = FALSE;
  171.         if (pSplitter != NULL)
  172.             bEnableScroll = pSplitter->DoScroll(pView, nTimerID, FALSE);
  173.         else
  174.             bEnableScroll = pView->OnScroll(nTimerID, 0, FALSE);
  175.         if (!bEnableScroll)
  176.             nTimerID = MAKEWORD(-1, -1);
  177.     }
  178.  
  179.     if (nTimerID == MAKEWORD(-1, -1))
  180.     {
  181.         if (m_nTimerID != MAKEWORD(-1, -1))
  182.         {
  183.             // send fake OnDragEnter when transition from scroll->normal
  184.             COleDataObject dataObject;
  185.             dataObject.Attach(m_lpDataObject, FALSE);
  186.             OnDragEnter(pWnd, &dataObject, dwKeyState, point);
  187.             m_nTimerID = MAKEWORD(-1, -1);
  188.         }
  189.         return DROPEFFECT_NONE;
  190.     }
  191.  
  192.     // save tick count when timer ID changes
  193.     DWORD dwTick = GetTickCount();
  194.     if (nTimerID != m_nTimerID)
  195.     {
  196.         m_dwLastTick = dwTick;
  197.         m_nScrollDelay = nScrollDelay;
  198.     }
  199.  
  200.     // scroll if necessary
  201.     if (dwTick - m_dwLastTick > m_nScrollDelay)
  202.     {
  203.         if (pSplitter != NULL)
  204.             pSplitter->DoScroll(pView, nTimerID, TRUE);
  205.         else
  206.             pView->OnScroll(nTimerID, 0, TRUE);
  207.         m_dwLastTick = dwTick;
  208.         m_nScrollDelay = nScrollInterval;
  209.     }
  210.     if (m_nTimerID == MAKEWORD(-1, -1))
  211.     {
  212.         // send fake OnDragLeave when transitioning from normal->scroll
  213.         OnDragLeave(pWnd);
  214.     }
  215.  
  216.     m_nTimerID = nTimerID;
  217.     // check for force link
  218. #ifndef _MAC
  219.     if ((dwKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
  220. #else
  221.     if ((dwKeyState & (MK_OPTION|MK_SHIFT)) == (MK_OPTION|MK_SHIFT))
  222. #endif
  223.         dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_LINK;
  224.     // check for force copy
  225. #ifndef _MAC
  226.     else if ((dwKeyState & MK_CONTROL) == MK_CONTROL)
  227. #else
  228.     else if ((dwKeyState & MK_OPTION) == MK_OPTION)
  229. #endif
  230.         dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_COPY;
  231.     // check for force move
  232.     else if ((dwKeyState & MK_ALT) == MK_ALT ||
  233.         (dwKeyState & MK_SHIFT) == MK_SHIFT)
  234.         dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
  235.     // default -- recommended action is move
  236.     else
  237.         dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
  238.     return dropEffect;
  239. }
  240.  
  241. /////////////////////////////////////////////////////////////////////////////
  242. // COleDropTarget drop/ drop query handling
  243.  
  244. DROPEFFECT COleDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject,
  245.     DWORD dwKeyState, CPoint point)
  246. {
  247.     ASSERT_VALID(this);
  248.  
  249.     if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  250.         return DROPEFFECT_NONE;
  251.  
  252.     // default delegates to view
  253.     CView* pView = (CView*)pWnd;
  254.     ASSERT_VALID(pView);
  255.     return pView->OnDragEnter(pDataObject, dwKeyState, point);
  256. }
  257.  
  258. DROPEFFECT COleDropTarget::OnDragOver(CWnd* pWnd, COleDataObject* pDataObject,
  259.     DWORD dwKeyState, CPoint point)
  260. {
  261.     ASSERT_VALID(this);
  262.  
  263.     if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  264.         return DROPEFFECT_NONE;
  265.  
  266.     // default delegates to view
  267.     CView* pView = (CView*)pWnd;
  268.     ASSERT_VALID(pView);
  269.     return pView->OnDragOver(pDataObject, dwKeyState, point);
  270. }
  271.  
  272. BOOL COleDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
  273.     DROPEFFECT dropEffect, CPoint point)
  274. {
  275.     ASSERT_VALID(this);
  276.  
  277.     if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  278.         return DROPEFFECT_NONE;
  279.  
  280.     // default delegates to view
  281.     CView* pView = (CView*)pWnd;
  282.     ASSERT_VALID(pView);
  283.     return pView->OnDrop(pDataObject, dropEffect, point);
  284. }
  285.  
  286. DROPEFFECT COleDropTarget::OnDropEx(CWnd* pWnd, COleDataObject* pDataObject,
  287.     DROPEFFECT dropEffect, DROPEFFECT dropEffectList, CPoint point)
  288. {
  289.     ASSERT_VALID(this);
  290.  
  291.     if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  292.         return (DROPEFFECT)-1;  // not implemented
  293.  
  294.     // default delegates to view
  295.     CView* pView = (CView*)pWnd;
  296.     ASSERT_VALID(pView);
  297.     return pView->OnDropEx(pDataObject, dropEffect, dropEffectList, point);
  298. }
  299.  
  300. void COleDropTarget::OnDragLeave(CWnd* pWnd)
  301. {
  302.     ASSERT_VALID(this);
  303.  
  304.     if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  305.         return;
  306.  
  307.     // default delegates to view
  308.     CView* pView = (CView*)pWnd;
  309.     ASSERT_VALID(pView);
  310.     pView->OnDragLeave();
  311.     return;
  312. }
  313.  
  314. /////////////////////////////////////////////////////////////////////////////
  315. // COleDropTarget::COleDropTarget implementation
  316.  
  317. BEGIN_INTERFACE_MAP(COleDropTarget, CCmdTarget)
  318.     INTERFACE_PART(COleDropTarget, IID_IDropTarget, DropTarget)
  319. END_INTERFACE_MAP()
  320.  
  321. STDMETHODIMP_(ULONG) COleDropTarget::XDropTarget::AddRef()
  322. {
  323.     METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
  324.     return pThis->ExternalAddRef();
  325. }
  326.  
  327. STDMETHODIMP_(ULONG) COleDropTarget::XDropTarget::Release()
  328. {
  329.     METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
  330.     return pThis->ExternalRelease();
  331. }
  332.  
  333. STDMETHODIMP COleDropTarget::XDropTarget::QueryInterface(
  334.     REFIID iid, LPVOID* ppvObj)
  335. {
  336.     METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
  337.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  338. }
  339.  
  340. // helper to filter out invalid DROPEFFECTs
  341. static DROPEFFECT AFXAPI
  342. FilterDropEffect(DROPEFFECT dropEffect, DROPEFFECT dwEffects)
  343. {
  344.     // return allowed dropEffect and DROPEFFECT_NONE
  345.     if ((dropEffect & dwEffects) != 0)
  346.         return dropEffect;
  347.  
  348.     // map common operations (copy/move) to alternates, but give negative
  349.     //  feedback for DROPEFFECT_LINK.
  350.     switch (dropEffect)
  351.     {
  352.     case DROPEFFECT_COPY:
  353.         if (dwEffects & DROPEFFECT_MOVE)
  354.             return DROPEFFECT_MOVE;
  355.         else if (dwEffects & DROPEFFECT_LINK)
  356.             return DROPEFFECT_LINK;
  357.         break;
  358.     case DROPEFFECT_MOVE:
  359.         if (dwEffects & DROPEFFECT_COPY)
  360.             return DROPEFFECT_COPY;
  361.         else if (dwEffects & DROPEFFECT_LINK)
  362.             return DROPEFFECT_LINK;
  363.         break;
  364.     case DROPEFFECT_LINK:
  365.         break;
  366.     }
  367.  
  368.     return DROPEFFECT_NONE;
  369. }
  370.  
  371. STDMETHODIMP COleDropTarget::XDropTarget::DragEnter(THIS_ LPDATAOBJECT lpDataObject,
  372.     DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect)
  373. {
  374.     METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
  375.     ASSERT_VALID(pThis);
  376.  
  377.     ASSERT(pdwEffect != NULL);
  378.     ASSERT(lpDataObject != NULL);
  379.  
  380.     SCODE sc = E_UNEXPECTED;
  381.     TRY
  382.     {
  383.         // cache lpDataObject
  384.         lpDataObject->AddRef();
  385.         RELEASE(pThis->m_lpDataObject);
  386.         pThis->m_lpDataObject = lpDataObject;
  387.  
  388.         CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
  389.         ASSERT_VALID(pWnd);
  390.         CPoint point((int)pt.x, (int)pt.y);
  391.         pWnd->ScreenToClient(&point);
  392.  
  393.         // check first for entering scroll area
  394.         DROPEFFECT dropEffect = pThis->OnDragScroll(pWnd, dwKeyState, point);
  395.         if ((dropEffect & DROPEFFECT_SCROLL) == 0)
  396.         {
  397.             // funnel through OnDragEnter since not in scroll region
  398.             COleDataObject dataObject;
  399.             dataObject.Attach(lpDataObject, FALSE);
  400.             dropEffect = pThis->OnDragEnter(pWnd, &dataObject, dwKeyState,
  401.                 point);
  402.         }
  403.         *pdwEffect = FilterDropEffect(dropEffect, *pdwEffect);
  404.         sc = S_OK;
  405.     }
  406.     END_TRY
  407.  
  408.     return sc;
  409. }
  410.  
  411. STDMETHODIMP COleDropTarget::XDropTarget::DragOver(THIS_ DWORD dwKeyState,
  412.     POINTL pt, LPDWORD pdwEffect)
  413. {
  414.     METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
  415.     ASSERT_VALID(pThis);
  416.  
  417.     ASSERT(pdwEffect != NULL);
  418.     ASSERT(pThis->m_lpDataObject != NULL);
  419.  
  420.     SCODE sc = E_UNEXPECTED;
  421.     TRY
  422.     {
  423.         CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
  424.         ASSERT_VALID(pWnd);
  425.         CPoint point((int)pt.x, (int)pt.y);
  426.         pWnd->ScreenToClient(&point);
  427.  
  428.         // check first for entering scroll area
  429.         DROPEFFECT dropEffect = pThis->OnDragScroll(pWnd, dwKeyState, point);
  430.         if ((dropEffect & DROPEFFECT_SCROLL) == 0)
  431.         {
  432.             // funnel through OnDragOver
  433.             COleDataObject dataObject;
  434.             dataObject.Attach(pThis->m_lpDataObject, FALSE);
  435.             dropEffect = pThis->OnDragOver(pWnd, &dataObject, dwKeyState,
  436.                 point);
  437.         }
  438.         *pdwEffect = FilterDropEffect(dropEffect, *pdwEffect);
  439.         sc = S_OK;
  440.     }
  441.     END_TRY
  442.  
  443.     return sc;
  444. }
  445.  
  446. STDMETHODIMP COleDropTarget::XDropTarget::DragLeave(THIS)
  447. {
  448.     METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
  449.     ASSERT_VALID(pThis);
  450.  
  451.     CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
  452.     ASSERT_VALID(pWnd);
  453.  
  454.     // cancel drag scrolling
  455.     pThis->m_nTimerID = MAKEWORD(-1, -1);
  456.  
  457.     // allow derivative to do own cleanup
  458.     COleDataObject dataObject;
  459.     dataObject.Attach(pThis->m_lpDataObject, FALSE);
  460.     pThis->OnDragLeave(pWnd);
  461.  
  462.     // release cached data object
  463.     RELEASE(pThis->m_lpDataObject);
  464.  
  465.     return S_OK;
  466. }
  467.  
  468. STDMETHODIMP COleDropTarget::XDropTarget::Drop(THIS_ LPDATAOBJECT lpDataObject,
  469.     DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect)
  470. {
  471.     METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
  472.     ASSERT_VALID(pThis);
  473.  
  474.     ASSERT(pdwEffect != NULL);
  475.     ASSERT(lpDataObject != NULL);
  476.  
  477.     SCODE sc = E_UNEXPECTED;
  478.     TRY
  479.     {
  480.         // cancel drag scrolling
  481.         pThis->m_nTimerID = MAKEWORD(-1, -1);
  482.  
  483.         // prepare for call to OnDragOver
  484.         CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
  485.         ASSERT_VALID(pWnd);
  486.         COleDataObject dataObject;
  487.         dataObject.Attach(lpDataObject, FALSE);
  488.         CPoint point((int)pt.x, (int)pt.y);
  489.         pWnd->ScreenToClient(&point);
  490.  
  491.         // verify that drop is legal
  492.         DROPEFFECT dropEffect = FilterDropEffect(pThis->OnDragOver(pWnd,
  493.             &dataObject, dwKeyState, point), *pdwEffect);
  494.  
  495.         // execute the drop (try OnDropEx then OnDrop for backward compatibility)
  496.         DROPEFFECT temp = pThis->OnDropEx(pWnd, &dataObject, dropEffect, *pdwEffect, point);
  497.         if (temp != -1)
  498.         {
  499.             // OnDropEx was implemented, return its drop effect
  500.             dropEffect = temp;
  501.         }
  502.         else if (dropEffect != DROPEFFECT_NONE)
  503.         {
  504.             // OnDropEx not implemented
  505.             if (!pThis->OnDrop(pWnd, &dataObject, dropEffect, point))
  506.                 dropEffect = DROPEFFECT_NONE;
  507.         }
  508.         else
  509.         {
  510.             // drop not accepted, allow cleanup
  511.             pThis->OnDragLeave(pWnd);
  512.         }
  513.  
  514.         // release potentially cached data object
  515.         RELEASE(pThis->m_lpDataObject);
  516.         *pdwEffect = dropEffect;
  517.         sc = S_OK;
  518.     }
  519.     END_TRY
  520.  
  521.     return sc;
  522. }
  523.  
  524. /////////////////////////////////////////////////////////////////////////////
  525. // COleDropTarget diagnostics
  526.  
  527. #ifdef _DEBUG
  528. void COleDropTarget::AssertValid() const
  529. {
  530.     CCmdTarget::AssertValid();
  531.     if (m_lpDataObject != NULL)
  532.         CWnd::FromHandle(m_hWnd)->AssertValid();
  533. }
  534.  
  535. void COleDropTarget::Dump(CDumpContext& dc) const
  536. {
  537.     CCmdTarget::Dump(dc);
  538.  
  539.     dc << "m_hWnd = " << m_hWnd;
  540.     dc << "\nm_lpDataObject = " << m_lpDataObject;
  541.     dc << "\nm_nTimerID = " << m_nTimerID;
  542.     dc << "\nm_dwLastTick = " << m_dwLastTick;
  543.  
  544.     dc << "\n";
  545. }
  546. #endif
  547.  
  548. /////////////////////////////////////////////////////////////////////////////
  549.