Implement a Drop Source Object with IDropSource

As mentioned earlier, Cosmo's drop source object is CDropSource in DROPSRC.CPP. Because Cosmo's needs are trivial, so is the implementation of the important IDropSource members:


STDMETHODIMP CDropSource::QueryContinueDrag(BOOL fEsc
, DWORD grfKeyState)
{
if (fEsc)
return ResultFromScode(DRAGDROP_S_CANCEL);

if (!(grfKeyState & MK_LBUTTON))
return ResultFromScode(DRAGDROP_S_DROP);

return NOERROR;
}


STDMETHODIMP CDropSource::GiveFeedback(DWORD dwEffect)
{
return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
}

The arguments to QueryContinueDrag describe the current keyboard and mouse states. The fEsc flag will be TRUE if the Esc key is pressed, meaning that we cancel the operation by returning DRAGDROP_S_CANCEL. This tells DoDragDrop to clean up and end the operation without the exchange of any data having occurred. The grfKeyState argument contains the states of the Ctrl, Alt, and Shift keys as well as the states of the left, middle, and right mouse buttons. All of these have corresponding MK_* values from WINDOWS.H (MK_LBUTTON, MK_RBUTTON, MK_MBUTTON, MK_SHIFT, and MK_CONTROL) except for MK_ALT, which is defined by OLE itself. The flags that appear in grfKeyState indicate the keys and buttons that are currently pressed.

Cosmo's implementation above checks whether the left mouse button is no longer pressed, and if it is, Cosmo returns DRAGDROP_S_DROP to cause a call to IDropTarget::Drop in order for DoDragDrop to return successfully. You can use any mouse button to cause a drop, modified with the Alt key if desired. However, you cannot use Ctrl and Shift because they modify the operation as a whole and might change during the operation without causing a drop. They are included in grfKeyState for the source's information. In any case, if the source does not detect appropriate drop conditions, it returns NOERROR from QueryContinueDrag to continue the operation.

If you think QueryContinueDrag is trivial (as it will be for most applications!), GiveFeedback is even simpler. If you want to use the standard mouse cursors, return DRAGDROP_S_USEDEFAULTCURSORS as shown earlier, which tells DoDragDrop to call the Windows function SetCursor with the appropriate mouse cursor. Otherwise, you can load your own cursor and call SetCursor yourself. If you need to know where the mouse is, call the Windows function or GetCursorPos.

Note: GiveFeedback is called many times during the course of an operation, so you should keep the code optimized and preload any needed cursors elsewhere to avoid the overhead here.