// 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 ///////////////////////////////////////////////////////////////////////////// // COleDropSource implementation AFX_DATADEF UINT COleDropSource::nDragMinDist; AFX_DATADEF UINT COleDropSource::nDragDelay; COleDropSource::COleDropSource() { m_bDragStarted = FALSE; m_dwButtonCancel = 0; m_dwButtonDrop = 0; AfxLockGlobals(CRIT_DROPSOURCE); static BOOL bInitialized; if (!bInitialized) { // get drag metrics from win.ini static const TCHAR szWindows[] = _T("windows"); static const TCHAR szDragMinDist[] = _T("DragMinDist"); static const TCHAR szDragDelay[] = _T("DragDelay"); nDragMinDist = GetProfileInt(szWindows, szDragMinDist, DD_DEFDRAGMINDIST); nDragDelay = GetProfileInt(szWindows, szDragDelay, DD_DEFDRAGDELAY); // now initialized, no need to call Initialize any more bInitialized = TRUE; } AfxUnlockGlobals(CRIT_DROPSOURCE); ASSERT_VALID(this); } SCODE COleDropSource::QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState) { ASSERT_VALID(this); // check escape key or right button -- and cancel if (bEscapePressed || (dwKeyState & m_dwButtonCancel) != 0) { m_bDragStarted = FALSE; // avoid unecessary cursor setting return DRAGDROP_S_CANCEL; } // check left-button up to end drag/drop and do the drop if ((dwKeyState & m_dwButtonDrop) == 0) return m_bDragStarted ? DRAGDROP_S_DROP : DRAGDROP_S_CANCEL; // otherwise, keep polling... return S_OK; } SCODE COleDropSource::GiveFeedback(DROPEFFECT /*dropEffect*/) { ASSERT_VALID(this); // don't change the cursor until drag is officially started return m_bDragStarted ? DRAGDROP_S_USEDEFAULTCURSORS : S_OK; } BOOL COleDropSource::OnBeginDrag(CWnd* pWnd) { ASSERT_VALID(this); m_bDragStarted = FALSE; // opposite button cancels drag operation m_dwButtonCancel = 0; m_dwButtonDrop = 0; if (GetKeyState(VK_LBUTTON) < 0) { m_dwButtonDrop |= MK_LBUTTON; m_dwButtonCancel |= MK_RBUTTON; } else if (GetKeyState(VK_RBUTTON) < 0) { m_dwButtonDrop |= MK_RBUTTON; m_dwButtonCancel |= MK_LBUTTON; } DWORD dwLastTick = GetTickCount(); pWnd->SetCapture(); while (!m_bDragStarted) { // some applications steal capture away at random times if (CWnd::GetCapture() != pWnd) break; // peek for next input message MSG msg; if (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) || PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) { // check for button cancellation (any button down will cancel) if (msg.message == WM_LBUTTONUP || msg.message == WM_RBUTTONUP || msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN) break; // check for keyboard cancellation if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) break; // check for drag start transition m_bDragStarted = !m_rectStartDrag.PtInRect(msg.pt); } // if the user sits here long enough, we eventually start the drag if (GetTickCount() - dwLastTick > nDragDelay) m_bDragStarted = TRUE; } ReleaseCapture(); return m_bDragStarted; } BEGIN_INTERFACE_MAP(COleDropSource, CCmdTarget) INTERFACE_PART(COleDropSource, IID_IDropSource, DropSource) END_INTERFACE_MAP() STDMETHODIMP_(ULONG) COleDropSource::XDropSource::AddRef() { METHOD_PROLOGUE_EX_(COleDropSource, DropSource) return pThis->ExternalAddRef(); } STDMETHODIMP_(ULONG) COleDropSource::XDropSource::Release() { METHOD_PROLOGUE_EX_(COleDropSource, DropSource) return pThis->ExternalRelease(); } STDMETHODIMP COleDropSource::XDropSource::QueryInterface( REFIID iid, LPVOID* ppvObj) { METHOD_PROLOGUE_EX_(COleDropSource, DropSource) return pThis->ExternalQueryInterface(&iid, ppvObj); } STDMETHODIMP COleDropSource::XDropSource::QueryContinueDrag( THIS_ BOOL fEscapePressed, DWORD dwKeyState) { METHOD_PROLOGUE_EX_(COleDropSource, DropSource) return pThis->QueryContinueDrag(fEscapePressed, dwKeyState); } STDMETHODIMP COleDropSource::XDropSource::GiveFeedback(THIS_ DWORD dwEffect) { METHOD_PROLOGUE_EX(COleDropSource, DropSource) ASSERT_VALID(pThis); return pThis->GiveFeedback(dwEffect); } ///////////////////////////////////////////////////////////////////////////// // helper for doing drag/drop with COleDataSource object DROPEFFECT COleDataSource::DoDragDrop(DWORD dwEffects, LPCRECT lpRectStartDrag, COleDropSource* pDropSource) { ASSERT_VALID(this); if (pDropSource != NULL) ASSERT_VALID(pDropSource); ASSERT(lpRectStartDrag == NULL || AfxIsValidAddress(lpRectStartDrag, sizeof(RECT), FALSE)); // use standard drop source implementation if one not provided COleDropSource dropSource; if (pDropSource == NULL) pDropSource = &dropSource; // setup drag/drop sensitivity rect pDropSource->m_bDragStarted = FALSE; if (lpRectStartDrag != NULL) { // set drop source drag start rect to parameter provided pDropSource->m_rectStartDrag.CopyRect(lpRectStartDrag); } else { // otherwise start with default empty rectangle around current point CPoint ptCursor; GetCursorPos(&ptCursor); pDropSource->m_rectStartDrag.SetRect( ptCursor.x, ptCursor.y, ptCursor.x, ptCursor.y); } if (pDropSource->m_rectStartDrag.IsRectNull()) { // null rect specifies no OnBeginDrag wait loop pDropSource->m_bDragStarted = TRUE; } else if (pDropSource->m_rectStartDrag.IsRectEmpty()) { // empty rect specifies drag drop around starting point pDropSource->m_rectStartDrag.InflateRect( COleDropSource::nDragMinDist, COleDropSource::nDragMinDist); } ASSERT_VALID(pDropSource); // before calling OLE drag/drop code, wait for mouse to move outside // the rectangle ASSERT_VALID(AfxGetMainWnd()); if (!pDropSource->OnBeginDrag(AfxGetMainWnd())) return DROPEFFECT_NONE; // call global OLE api to do the drag drop LPDATAOBJECT lpDataObject = (LPDATAOBJECT)GetInterface(&IID_IDataObject); LPDROPSOURCE lpDropSource = (LPDROPSOURCE)pDropSource->GetInterface(&IID_IDropSource); DWORD dwResultEffect = DROPEFFECT_NONE; ::DoDragDrop(lpDataObject, lpDropSource, dwEffects, &dwResultEffect); return dwResultEffect; } ///////////////////////////////////////////////////////////////////////////// // COleDropSource diagnostics #ifdef _DEBUG void COleDropSource::Dump(CDumpContext& dc) const { CCmdTarget::Dump(dc); dc << "m_bDragStarted = " << m_bDragStarted; dc << "\nm_rectStartDrag.left = " << m_rectStartDrag.left; dc << "\nm_rectStartDrag.top = " << m_rectStartDrag.top; dc << "\nm_rectStartDrag.right = " << m_rectStartDrag.right; dc << "\nm_rectStartDrag.bottom = " << m_rectStartDrag.bottom; dc << "\n"; } #endif /////////////////////////////////////////////////////////////////////////////