idropsourceimpl.h
来自「《ATL深入解析》随书源码」· C头文件 代码 · 共 195 行
H
195 行
// IDropSourceImpl.h: interface for the IDropSourceImpl class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_IDROPSOURCEIMPL_H__6ED143B2_4A64_11D2_BCF0_00A0C9C8E50D__INCLUDED_)
#define AFX_IDROPSOURCEIMPL_H__6ED143B2_4A64_11D2_BCF0_00A0C9C8E50D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
template <class T>
class ATL_NO_VTABLE IDropSourceImpl : public IDropSource
{
public:
IDropSourceImpl()
{
m_bDragStarted = false;
m_dwButtonCancel = 0;
m_dwButtonDrop = 0;
}
virtual ~IDropSourceImpl() {}
static void WINAPI ObjectMain(bool /* bStarting */)
{
// 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);
}
DWORD DoDragDrop(DWORD dwEffects, LPCRECT lpRectStartDrag)
{
ATLTRACE2(atlTraceCOM, 0, _T("IDropSourceImpl::DoDragDrop\n"));
T* pT = static_cast<T*>(this);
// setup drag/drop sensitivity rect
m_bDragStarted = false;
if (lpRectStartDrag != NULL) {
// set drop source drag start rect to parameter provided
m_rectStartDrag.CopyRect(lpRectStartDrag);
}
else {
// otherwise start with default empty rectangle around current point
CPoint ptCursor;
GetCursorPos(&ptCursor);
m_rectStartDrag.SetRect(
ptCursor.x, ptCursor.y, ptCursor.x, ptCursor.y);
}
if (m_rectStartDrag.IsRectNull()) {
// null rect specifies no OnBeginDrag wait loop
m_bDragStarted = true;
}
else if (m_rectStartDrag.IsRectEmpty()) {
// empty rect specifies drag drop around starting point
m_rectStartDrag.InflateRect(nDragMinDist, nDragMinDist);
}
// before calling OLE drag/drop code, wait for mouse to move outside
// the rectangle
if (!OnBeginDrag(pT))
return DROPEFFECT_NONE;
// call global OLE api to do the drag drop
CComPtr<IDataObject> spDataObject ;
HRESULT hr = pT->_InternalQueryInterface (IID_IDataObject, (void**) &spDataObject);
ATLASSERT (SUCCEEDED (hr));
CComPtr<IDropSource> spDropSource ;
hr = pT->_InternalQueryInterface (IID_IDropSource, (void**) &spDropSource);
ATLASSERT (SUCCEEDED (hr));
DWORD dwResultEffect = DROPEFFECT_NONE;
::DoDragDrop(spDataObject, spDropSource, dwEffects, &dwResultEffect);
return dwResultEffect;
}
// Implementation
public:
// IDropSource
STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState)
{
ATLTRACE2(atlTraceCOM, 0, _T("IDropSourceImpl::QueryContinueDrag\n"));
T* pT = static_cast<T*>(this);
// check escape key or right button -- and cancel
if (fEscapePressed || (grfKeyState & m_dwButtonCancel) != 0) {
m_bDragStarted = false; // avoid unecessary cursor setting
return DRAGDROP_S_CANCEL;
}
// check left/right-button up to end drag/drop and do the drop
if ((grfKeyState & m_dwButtonDrop) == 0)
return m_bDragStarted ? DRAGDROP_S_DROP : DRAGDROP_S_CANCEL;
// otherwise, keep polling...
return S_OK;
}
STDMETHOD(GiveFeedback)(DWORD)
{
ATLTRACE2(atlTraceCOM, 0, _T("IDropSourceImpl::GiveFeedback\n"));
T* pT = static_cast<T*>(this);
// don't change the cursor until drag is officially started
return m_bDragStarted ? DRAGDROP_S_USEDEFAULTCURSORS : S_OK;
}
virtual bool OnBeginDrag(CWindow* pWnd)
{
ATLTRACE2(atlTraceCOM, 0, _T("IDropSourceImpl::OnBeginDrag\n"));
T* pT = static_cast<T*>(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();
if (pT->m_bWndLess) {
HRESULT hr = pT->m_spInPlaceSite->SetCapture(TRUE);
}
else
pWnd->SetCapture();
while (!m_bDragStarted) {
// some applications steal capture away at random times
if (pT->m_bWndLess) {
if (S_FALSE == pT->m_spInPlaceSite->GetCapture())
break ;
}
else
if (::GetCapture() != pWnd->m_hWnd)
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;
}
if (pT->m_bWndLess) {
HRESULT hr = pT->m_spInPlaceSite->SetCapture(FALSE);
}
else
ReleaseCapture();
return m_bDragStarted;
}
CRect m_rectStartDrag; // when mouse leaves this rect, drag drop starts
bool m_bDragStarted; // has drag really started yet?
DWORD m_dwButtonCancel; // which button will cancel (going down)
DWORD m_dwButtonDrop; // which button will confirm (going up)
// metrics for drag start determination
static UINT nDragMinDist; // min. amount mouse must move for drag
static UINT nDragDelay; // delay before drag starts
};
template <class T> UINT IDropSourceImpl<T>::nDragMinDist;
template <class T> UINT IDropSourceImpl<T>::nDragDelay;
#endif // !defined(AFX_IDROPSOURCEIMPL_H__6ED143B2_4A64_11D2_BCF0_00A0C9C8E50D__INCLUDED_)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?