Drag & Drop
MFC drag&drop有两种:OLE拖放和文件管理器(WM_DROPFILES消息)拖放。这是两种不同的机制。
OLE拖放的实现 - Drop的实现 - COleDropTarget
Drop里面很明确的先使用OnDropEx处理drop操作,如果OnDropEx没有处理成功,就让给OnDrop处理。这个优先级要清楚。
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);
if (lpDataObject == NULL || pdwEffect == NULL)
{
return E_INVALIDARG;
}
SCODE sc = E_UNEXPECTED;
TRY
{
// cancel drag scrolling
pThis->m_nTimerID = 0xffff;
// 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;
}
下面是拖动过程控制的3个函数
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);
if (lpDataObject == NULL || pdwEffect == NULL)
{
return E_INVALIDARG;
}
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