home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
-
- #ifdef AFX_OLE4_SEG
- #pragma code_seg(AFX_OLE4_SEG)
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- #define new DEBUG_NEW
-
- /////////////////////////////////////////////////////////////////////////////
- // COleDropTarget implementation
-
- AFX_DATADEF int COleDropTarget::nScrollInset;
- AFX_DATADEF UINT COleDropTarget::nScrollDelay;
- AFX_DATADEF UINT COleDropTarget::nScrollInterval;
-
- COleDropTarget::COleDropTarget()
- {
- // initialize local state
- m_hWnd = NULL;
- m_lpDataObject = NULL;
- m_nTimerID = MAKEWORD(-1, -1);
-
- AfxLockGlobals(CRIT_DROPTARGET);
- static BOOL bInitialized;
- if (!bInitialized)
- {
- // get scroll metrics from win.ini
- static const TCHAR szWindows[] = _T("windows");
- static const TCHAR szScrollDelay[] = _T("DragScrollDelay");
- static const TCHAR szScrollInset[] = _T("DragScrollInset");
- static const TCHAR szScrollInterval[] = _T("DragScrollInterval");
-
- nScrollInset = GetProfileInt(szWindows, szScrollInset, DD_DEFSCROLLINSET);
- nScrollDelay = GetProfileInt(szWindows, szScrollDelay, DD_DEFSCROLLDELAY);
- nScrollInterval = GetProfileInt(szWindows, szScrollInterval,
- DD_DEFSCROLLINTERVAL);
-
- // now initialized, no need to call Initialize any more
- bInitialized = TRUE;
- }
- AfxUnlockGlobals(CRIT_DROPTARGET);
-
- ASSERT_VALID(this);
- }
-
- COleDropTarget::~COleDropTarget()
- {
- ASSERT_VALID(this);
-
- if (m_hWnd != NULL)
- {
- TRACE0("COleDropTarget::Revoke not called before destructor --\n");
- TRACE0("\tmay cause RIPs under debug Windows.\n");
- Revoke();
- }
- }
-
- BOOL COleDropTarget::Register(CWnd* pWnd)
- {
- ASSERT_VALID(this);
- ASSERT(m_hWnd == NULL); // registering drop target twice?
- ASSERT_VALID(pWnd);
-
- LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
- ASSERT(lpUnknown != NULL);
-
- // the object must be locked externally to keep LRPC connections alive
- if (CoLockObjectExternal(lpUnknown, TRUE, FALSE) != S_OK)
- return FALSE;
-
- // connect the HWND to the IDropTarget implementation
- if (RegisterDragDrop(pWnd->m_hWnd,
- (LPDROPTARGET)GetInterface(&IID_IDropTarget)) != S_OK)
- {
- CoLockObjectExternal(lpUnknown, FALSE, FALSE);
- return FALSE;
- }
-
- // connect internal data
- m_hWnd = pWnd->m_hWnd;
- ASSERT(pWnd->m_pDropTarget == NULL);
- pWnd->m_pDropTarget = this;
-
- return TRUE;
- }
-
- void COleDropTarget::Revoke()
- {
- ASSERT_VALID(this);
- ASSERT(m_lpDataObject == NULL);
-
- if (m_hWnd == NULL)
- {
- ASSERT(m_nTimerID == MAKEWORD(-1, -1));
- return;
- }
-
- // disconnect from OLE
- RevokeDragDrop(m_hWnd);
- CoLockObjectExternal((LPUNKNOWN)GetInterface(&IID_IUnknown), FALSE, TRUE);
-
- // disconnect internal data
- CWnd::FromHandle(m_hWnd)->m_pDropTarget = NULL;
- m_hWnd = NULL;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // default implementation of drag/drop scrolling
-
- DROPEFFECT COleDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState,
- CPoint point)
- {
- ASSERT_VALID(this);
- ASSERT_VALID(pWnd);
-
- // CWnds are allowed, but don't support autoscrolling
- if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
- return DROPEFFECT_NONE;
- CView* pView = (CView*)pWnd;
- DROPEFFECT dropEffect = pView->OnDragScroll(dwKeyState, point);
-
- // DROPEFFECT_SCROLL means do the default
- if (dropEffect != DROPEFFECT_SCROLL)
- return dropEffect;
-
- // get client rectangle of destination window
- CRect rectClient;
- pWnd->GetClientRect(&rectClient);
- CRect rect = rectClient;
-
- // hit-test against inset region
- UINT nTimerID = MAKEWORD(-1, -1);
- rect.InflateRect(-nScrollInset, -nScrollInset);
- CSplitterWnd* pSplitter = NULL;
- if (rectClient.PtInRect(point) && !rect.PtInRect(point))
- {
- // determine which way to scroll along both X & Y axis
- if (point.x < rect.left)
- nTimerID = MAKEWORD(SB_LINEUP, HIBYTE(nTimerID));
- else if (point.x >= rect.right)
- nTimerID = MAKEWORD(SB_LINEDOWN, HIBYTE(nTimerID));
- if (point.y < rect.top)
- nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEUP);
- else if (point.y >= rect.bottom)
- nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEDOWN);
- ASSERT(nTimerID != MAKEWORD(-1, -1));
-
- // check for valid scroll first
- pSplitter = CView::GetParentSplitter(pView, FALSE);
- BOOL bEnableScroll = FALSE;
- if (pSplitter != NULL)
- bEnableScroll = pSplitter->DoScroll(pView, nTimerID, FALSE);
- else
- bEnableScroll = pView->OnScroll(nTimerID, 0, FALSE);
- if (!bEnableScroll)
- nTimerID = MAKEWORD(-1, -1);
- }
-
- if (nTimerID == MAKEWORD(-1, -1))
- {
- if (m_nTimerID != MAKEWORD(-1, -1))
- {
- // send fake OnDragEnter when transition from scroll->normal
- COleDataObject dataObject;
- dataObject.Attach(m_lpDataObject, FALSE);
- OnDragEnter(pWnd, &dataObject, dwKeyState, point);
- m_nTimerID = MAKEWORD(-1, -1);
- }
- return DROPEFFECT_NONE;
- }
-
- // save tick count when timer ID changes
- DWORD dwTick = GetTickCount();
- if (nTimerID != m_nTimerID)
- {
- m_dwLastTick = dwTick;
- m_nScrollDelay = nScrollDelay;
- }
-
- // scroll if necessary
- if (dwTick - m_dwLastTick > m_nScrollDelay)
- {
- if (pSplitter != NULL)
- pSplitter->DoScroll(pView, nTimerID, TRUE);
- else
- pView->OnScroll(nTimerID, 0, TRUE);
- m_dwLastTick = dwTick;
- m_nScrollDelay = nScrollInterval;
- }
- if (m_nTimerID == MAKEWORD(-1, -1))
- {
- // send fake OnDragLeave when transitioning from normal->scroll
- OnDragLeave(pWnd);
- }
-
- m_nTimerID = nTimerID;
- // check for force link
- if ((dwKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
- dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_LINK;
- // check for force copy
- else if ((dwKeyState & MK_CONTROL) == MK_CONTROL)
- dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_COPY;
- // check for force move
- else if ((dwKeyState & MK_ALT) == MK_ALT ||
- (dwKeyState & MK_SHIFT) == MK_SHIFT)
- dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
- // default -- recommended action is move
- else
- dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
- return dropEffect;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // COleDropTarget drop/ drop query handling
-
- DROPEFFECT COleDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject,
- DWORD dwKeyState, CPoint point)
- {
- ASSERT_VALID(this);
-
- if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
- return DROPEFFECT_NONE;
-
- // default delegates to view
- CView* pView = (CView*)pWnd;
- ASSERT_VALID(pView);
- return pView->OnDragEnter(pDataObject, dwKeyState, point);
- }
-
- DROPEFFECT COleDropTarget::OnDragOver(CWnd* pWnd, COleDataObject* pDataObject,
- DWORD dwKeyState, CPoint point)
- {
- ASSERT_VALID(this);
-
- if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
- return DROPEFFECT_NONE;
-
- // default delegates to view
- CView* pView = (CView*)pWnd;
- ASSERT_VALID(pView);
- return pView->OnDragOver(pDataObject, dwKeyState, point);
- }
-
- BOOL COleDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
- DROPEFFECT dropEffect, CPoint point)
- {
- ASSERT_VALID(this);
-
- if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
- return DROPEFFECT_NONE;
-
- // default delegates to view
- CView* pView = (CView*)pWnd;
- ASSERT_VALID(pView);
- return pView->OnDrop(pDataObject, dropEffect, point);
- }
-
- DROPEFFECT COleDropTarget::OnDropEx(CWnd* pWnd, COleDataObject* pDataObject,
- DROPEFFECT dropEffect, DROPEFFECT dropEffectList, CPoint point)
- {
- ASSERT_VALID(this);
-
- if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
- return (DROPEFFECT)-1; // not implemented
-
- // default delegates to view
- CView* pView = (CView*)pWnd;
- ASSERT_VALID(pView);
- return pView->OnDropEx(pDataObject, dropEffect, dropEffectList, point);
- }
-
- void COleDropTarget::OnDragLeave(CWnd* pWnd)
- {
- ASSERT_VALID(this);
-
- if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
- return;
-
- // default delegates to view
- CView* pView = (CView*)pWnd;
- ASSERT_VALID(pView);
- pView->OnDragLeave();
- return;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // COleDropTarget::COleDropTarget implementation
-
- BEGIN_INTERFACE_MAP(COleDropTarget, CCmdTarget)
- INTERFACE_PART(COleDropTarget, IID_IDropTarget, DropTarget)
- END_INTERFACE_MAP()
-
- STDMETHODIMP_(ULONG) COleDropTarget::XDropTarget::AddRef()
- {
- METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
- return pThis->ExternalAddRef();
- }
-
- STDMETHODIMP_(ULONG) COleDropTarget::XDropTarget::Release()
- {
- METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
- return pThis->ExternalRelease();
- }
-
- STDMETHODIMP COleDropTarget::XDropTarget::QueryInterface(
- REFIID iid, LPVOID* ppvObj)
- {
- METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
- return pThis->ExternalQueryInterface(&iid, ppvObj);
- }
-
- // helper to filter out invalid DROPEFFECTs
- AFX_STATIC DROPEFFECT AFXAPI
- _AfxFilterDropEffect(DROPEFFECT dropEffect, DROPEFFECT dwEffects)
- {
- // return allowed dropEffect and DROPEFFECT_NONE
- if ((dropEffect & dwEffects) != 0)
- return dropEffect;
-
- // map common operations (copy/move) to alternates, but give negative
- // feedback for DROPEFFECT_LINK.
- switch (dropEffect)
- {
- case DROPEFFECT_COPY:
- if (dwEffects & DROPEFFECT_MOVE)
- return DROPEFFECT_MOVE;
- else if (dwEffects & DROPEFFECT_LINK)
- return DROPEFFECT_LINK;
- break;
- case DROPEFFECT_MOVE:
- if (dwEffects & DROPEFFECT_COPY)
- return DROPEFFECT_COPY;
- else if (dwEffects & DROPEFFECT_LINK)
- return DROPEFFECT_LINK;
- break;
- case DROPEFFECT_LINK:
- break;
- }
-
- return DROPEFFECT_NONE;
- }
-
- STDMETHODIMP COleDropTarget::XDropTarget::DragEnter(THIS_ LPDATAOBJECT lpDataObject,
- DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect)
- {
- METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
- ASSERT_VALID(pThis);
-
- ASSERT(pdwEffect != NULL);
- ASSERT(lpDataObject != NULL);
-
- SCODE sc = E_UNEXPECTED;
- TRY
- {
- // cache lpDataObject
- lpDataObject->AddRef();
- RELEASE(pThis->m_lpDataObject);
- pThis->m_lpDataObject = lpDataObject;
-
- CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
- ASSERT_VALID(pWnd);
- CPoint point((int)pt.x, (int)pt.y);
- pWnd->ScreenToClient(&point);
-
- // check first for entering scroll area
- DROPEFFECT dropEffect = pThis->OnDragScroll(pWnd, dwKeyState, point);
- if ((dropEffect & DROPEFFECT_SCROLL) == 0)
- {
- // funnel through OnDragEnter since not in scroll region
- COleDataObject dataObject;
- dataObject.Attach(lpDataObject, FALSE);
- dropEffect = pThis->OnDragEnter(pWnd, &dataObject, dwKeyState,
- point);
- }
- *pdwEffect = _AfxFilterDropEffect(dropEffect, *pdwEffect);
- sc = S_OK;
- }
- END_TRY
-
- return sc;
- }
-
- STDMETHODIMP COleDropTarget::XDropTarget::DragOver(THIS_ DWORD dwKeyState,
- POINTL pt, LPDWORD pdwEffect)
- {
- METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
- ASSERT_VALID(pThis);
-
- ASSERT(pdwEffect != NULL);
- ASSERT(pThis->m_lpDataObject != NULL);
-
- SCODE sc = E_UNEXPECTED;
- TRY
- {
- CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
- ASSERT_VALID(pWnd);
- CPoint point((int)pt.x, (int)pt.y);
- pWnd->ScreenToClient(&point);
-
- // check first for entering scroll area
- DROPEFFECT dropEffect = pThis->OnDragScroll(pWnd, dwKeyState, point);
- if ((dropEffect & DROPEFFECT_SCROLL) == 0)
- {
- // funnel through OnDragOver
- COleDataObject dataObject;
- dataObject.Attach(pThis->m_lpDataObject, FALSE);
- dropEffect = pThis->OnDragOver(pWnd, &dataObject, dwKeyState,
- point);
- }
- *pdwEffect = _AfxFilterDropEffect(dropEffect, *pdwEffect);
- sc = S_OK;
- }
- END_TRY
-
- return sc;
- }
-
- STDMETHODIMP COleDropTarget::XDropTarget::DragLeave(THIS)
- {
- METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
- ASSERT_VALID(pThis);
-
- CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
- ASSERT_VALID(pWnd);
-
- // cancel drag scrolling
- pThis->m_nTimerID = MAKEWORD(-1, -1);
-
- // allow derivative to do own cleanup
- COleDataObject dataObject;
- dataObject.Attach(pThis->m_lpDataObject, FALSE);
- pThis->OnDragLeave(pWnd);
-
- // release cached data object
- RELEASE(pThis->m_lpDataObject);
-
- return S_OK;
- }
-
- STDMETHODIMP COleDropTarget::XDropTarget::Drop(THIS_ LPDATAOBJECT lpDataObject,
- DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect)
- {
- METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
- ASSERT_VALID(pThis);
-
- ASSERT(pdwEffect != NULL);
- ASSERT(lpDataObject != NULL);
-
- SCODE sc = E_UNEXPECTED;
- TRY
- {
- // cancel drag scrolling
- pThis->m_nTimerID = MAKEWORD(-1, -1);
-
- // prepare for call to OnDragOver
- CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
- ASSERT_VALID(pWnd);
- COleDataObject dataObject;
- dataObject.Attach(lpDataObject, FALSE);
- CPoint point((int)pt.x, (int)pt.y);
- pWnd->ScreenToClient(&point);
-
- // verify that drop is legal
- DROPEFFECT dropEffect = _AfxFilterDropEffect(pThis->OnDragOver(pWnd,
- &dataObject, dwKeyState, point), *pdwEffect);
-
- // execute the drop (try OnDropEx then OnDrop for backward compatibility)
- DROPEFFECT temp = pThis->OnDropEx(pWnd, &dataObject, dropEffect, *pdwEffect, point);
- if (temp != -1)
- {
- // OnDropEx was implemented, return its drop effect
- dropEffect = temp;
- }
- else if (dropEffect != DROPEFFECT_NONE)
- {
- // OnDropEx not implemented
- if (!pThis->OnDrop(pWnd, &dataObject, dropEffect, point))
- dropEffect = DROPEFFECT_NONE;
- }
- else
- {
- // drop not accepted, allow cleanup
- pThis->OnDragLeave(pWnd);
- }
-
- // release potentially cached data object
- RELEASE(pThis->m_lpDataObject);
- *pdwEffect = dropEffect;
- sc = S_OK;
- }
- END_TRY
-
- return sc;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // COleDropTarget diagnostics
-
- #ifdef _DEBUG
- void COleDropTarget::AssertValid() const
- {
- CCmdTarget::AssertValid();
- if (m_lpDataObject != NULL)
- CWnd::FromHandle(m_hWnd)->AssertValid();
- }
-
- void COleDropTarget::Dump(CDumpContext& dc) const
- {
- CCmdTarget::Dump(dc);
-
- dc << "m_hWnd = " << m_hWnd;
- dc << "\nm_lpDataObject = " << m_lpDataObject;
- dc << "\nm_nTimerID = " << m_nTimerID;
- dc << "\nm_dwLastTick = " << m_dwLastTick;
-
- dc << "\n";
- }
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
-