oledrop2.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #ifdef AFX_OLE4_SEG
  12. #pragma code_seg(AFX_OLE4_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. /////////////////////////////////////////////////////////////////////////////
  20. // COleDropTarget implementation
  21. AFX_DATADEF int COleDropTarget::nScrollInset;
  22. AFX_DATADEF UINT COleDropTarget::nScrollDelay;
  23. AFX_DATADEF UINT COleDropTarget::nScrollInterval;
  24. COleDropTarget::COleDropTarget()
  25. {
  26. // initialize local state
  27. m_hWnd = NULL;
  28. m_lpDataObject = NULL;
  29. m_nTimerID = MAKEWORD(-1, -1);
  30. AfxLockGlobals(CRIT_DROPTARGET);
  31. static BOOL bInitialized;
  32. if (!bInitialized)
  33. {
  34. // get scroll metrics from win.ini
  35. static const TCHAR szWindows[] = _T("windows");
  36. static const TCHAR szScrollDelay[] = _T("DragScrollDelay");
  37. static const TCHAR szScrollInset[] = _T("DragScrollInset");
  38. static const TCHAR szScrollInterval[] = _T("DragScrollInterval");
  39. nScrollInset = GetProfileInt(szWindows, szScrollInset, DD_DEFSCROLLINSET);
  40. nScrollDelay = GetProfileInt(szWindows, szScrollDelay, DD_DEFSCROLLDELAY);
  41. nScrollInterval = GetProfileInt(szWindows, szScrollInterval,
  42. DD_DEFSCROLLINTERVAL);
  43. // now initialized, no need to call Initialize any more
  44. bInitialized = TRUE;
  45. }
  46. AfxUnlockGlobals(CRIT_DROPTARGET);
  47. ASSERT_VALID(this);
  48. }
  49. COleDropTarget::~COleDropTarget()
  50. {
  51. ASSERT_VALID(this);
  52. if (m_hWnd != NULL)
  53. {
  54. TRACE0("COleDropTarget::Revoke not called before destructor --\n");
  55. TRACE0("\tmay cause RIPs under debug Windows.\n");
  56. Revoke();
  57. }
  58. }
  59. BOOL COleDropTarget::Register(CWnd* pWnd)
  60. {
  61. ASSERT_VALID(this);
  62. ASSERT(m_hWnd == NULL); // registering drop target twice?
  63. ASSERT_VALID(pWnd);
  64. LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
  65. ASSERT(lpUnknown != NULL);
  66. // the object must be locked externally to keep LRPC connections alive
  67. if (CoLockObjectExternal(lpUnknown, TRUE, FALSE) != S_OK)
  68. return FALSE;
  69. // connect the HWND to the IDropTarget implementation
  70. if (RegisterDragDrop(pWnd->m_hWnd,
  71. (LPDROPTARGET)GetInterface(&IID_IDropTarget)) != S_OK)
  72. {
  73. CoLockObjectExternal(lpUnknown, FALSE, FALSE);
  74. return FALSE;
  75. }
  76. // connect internal data
  77. m_hWnd = pWnd->m_hWnd;
  78. ASSERT(pWnd->m_pDropTarget == NULL);
  79. pWnd->m_pDropTarget = this;
  80. return TRUE;
  81. }
  82. void COleDropTarget::Revoke()
  83. {
  84. ASSERT_VALID(this);
  85. ASSERT(m_lpDataObject == NULL);
  86. if (m_hWnd == NULL)
  87. {
  88. ASSERT(m_nTimerID == MAKEWORD(-1, -1));
  89. return;
  90. }
  91. // disconnect from OLE
  92. RevokeDragDrop(m_hWnd);
  93. CoLockObjectExternal((LPUNKNOWN)GetInterface(&IID_IUnknown), FALSE, TRUE);
  94. // disconnect internal data
  95. CWnd::FromHandle(m_hWnd)->m_pDropTarget = NULL;
  96. m_hWnd = NULL;
  97. }
  98. /////////////////////////////////////////////////////////////////////////////
  99. // default implementation of drag/drop scrolling
  100. DROPEFFECT COleDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState,
  101. CPoint point)
  102. {
  103. ASSERT_VALID(this);
  104. ASSERT_VALID(pWnd);
  105. // CWnds are allowed, but don't support autoscrolling
  106. if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  107. return DROPEFFECT_NONE;
  108. CView* pView = (CView*)pWnd;
  109. DROPEFFECT dropEffect = pView->OnDragScroll(dwKeyState, point);
  110. // DROPEFFECT_SCROLL means do the default
  111. if (dropEffect != DROPEFFECT_SCROLL)
  112. return dropEffect;
  113. // get client rectangle of destination window
  114. CRect rectClient;
  115. pWnd->GetClientRect(&rectClient);
  116. CRect rect = rectClient;
  117. // hit-test against inset region
  118. UINT nTimerID = MAKEWORD(-1, -1);
  119. rect.InflateRect(-nScrollInset, -nScrollInset);
  120. CSplitterWnd* pSplitter = NULL;
  121. if (rectClient.PtInRect(point) && !rect.PtInRect(point))
  122. {
  123. // determine which way to scroll along both X & Y axis
  124. if (point.x < rect.left)
  125. nTimerID = MAKEWORD(SB_LINEUP, HIBYTE(nTimerID));
  126. else if (point.x >= rect.right)
  127. nTimerID = MAKEWORD(SB_LINEDOWN, HIBYTE(nTimerID));
  128. if (point.y < rect.top)
  129. nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEUP);
  130. else if (point.y >= rect.bottom)
  131. nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEDOWN);
  132. ASSERT(nTimerID != MAKEWORD(-1, -1));
  133. // check for valid scroll first
  134. pSplitter = CView::GetParentSplitter(pView, FALSE);
  135. BOOL bEnableScroll = FALSE;
  136. if (pSplitter != NULL)
  137. bEnableScroll = pSplitter->DoScroll(pView, nTimerID, FALSE);
  138. else
  139. bEnableScroll = pView->OnScroll(nTimerID, 0, FALSE);
  140. if (!bEnableScroll)
  141. nTimerID = MAKEWORD(-1, -1);
  142. }
  143. if (nTimerID == MAKEWORD(-1, -1))
  144. {
  145. if (m_nTimerID != MAKEWORD(-1, -1))
  146. {
  147. // send fake OnDragEnter when transition from scroll->normal
  148. COleDataObject dataObject;
  149. dataObject.Attach(m_lpDataObject, FALSE);
  150. OnDragEnter(pWnd, &dataObject, dwKeyState, point);
  151. m_nTimerID = MAKEWORD(-1, -1);
  152. }
  153. return DROPEFFECT_NONE;
  154. }
  155. // save tick count when timer ID changes
  156. DWORD dwTick = GetTickCount();
  157. if (nTimerID != m_nTimerID)
  158. {
  159. m_dwLastTick = dwTick;
  160. m_nScrollDelay = nScrollDelay;
  161. }
  162. // scroll if necessary
  163. if (dwTick - m_dwLastTick > m_nScrollDelay)
  164. {
  165. if (pSplitter != NULL)
  166. pSplitter->DoScroll(pView, nTimerID, TRUE);
  167. else
  168. pView->OnScroll(nTimerID, 0, TRUE);
  169. m_dwLastTick = dwTick;
  170. m_nScrollDelay = nScrollInterval;
  171. }
  172. if (m_nTimerID == MAKEWORD(-1, -1))
  173. {
  174. // send fake OnDragLeave when transitioning from normal->scroll
  175. OnDragLeave(pWnd);
  176. }
  177. m_nTimerID = nTimerID;
  178. // check for force link
  179. if ((dwKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
  180. dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_LINK;
  181. // check for force copy
  182. else if ((dwKeyState & MK_CONTROL) == MK_CONTROL)
  183. dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_COPY;
  184. // check for force move
  185. else if ((dwKeyState & MK_ALT) == MK_ALT ||
  186. (dwKeyState & MK_SHIFT) == MK_SHIFT)
  187. dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
  188. // default -- recommended action is move
  189. else
  190. dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
  191. return dropEffect;
  192. }
  193. /////////////////////////////////////////////////////////////////////////////
  194. // COleDropTarget drop/ drop query handling
  195. DROPEFFECT COleDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject,
  196. DWORD dwKeyState, CPoint point)
  197. {
  198. ASSERT_VALID(this);
  199. if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  200. return DROPEFFECT_NONE;
  201. // default delegates to view
  202. CView* pView = (CView*)pWnd;
  203. ASSERT_VALID(pView);
  204. return pView->OnDragEnter(pDataObject, dwKeyState, point);
  205. }
  206. DROPEFFECT COleDropTarget::OnDragOver(CWnd* pWnd, COleDataObject* pDataObject,
  207. DWORD dwKeyState, CPoint point)
  208. {
  209. ASSERT_VALID(this);
  210. if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  211. return DROPEFFECT_NONE;
  212. // default delegates to view
  213. CView* pView = (CView*)pWnd;
  214. ASSERT_VALID(pView);
  215. return pView->OnDragOver(pDataObject, dwKeyState, point);
  216. }
  217. BOOL COleDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
  218. DROPEFFECT dropEffect, CPoint point)
  219. {
  220. ASSERT_VALID(this);
  221. if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  222. return DROPEFFECT_NONE;
  223. // default delegates to view
  224. CView* pView = (CView*)pWnd;
  225. ASSERT_VALID(pView);
  226. return pView->OnDrop(pDataObject, dropEffect, point);
  227. }
  228. DROPEFFECT COleDropTarget::OnDropEx(CWnd* pWnd, COleDataObject* pDataObject,
  229. DROPEFFECT dropEffect, DROPEFFECT dropEffectList, CPoint point)
  230. {
  231. ASSERT_VALID(this);
  232. if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  233. return (DROPEFFECT)-1; // not implemented
  234. // default delegates to view
  235. CView* pView = (CView*)pWnd;
  236. ASSERT_VALID(pView);
  237. return pView->OnDropEx(pDataObject, dropEffect, dropEffectList, point);
  238. }
  239. void COleDropTarget::OnDragLeave(CWnd* pWnd)
  240. {
  241. ASSERT_VALID(this);
  242. if (!pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  243. return;
  244. // default delegates to view
  245. CView* pView = (CView*)pWnd;
  246. ASSERT_VALID(pView);
  247. pView->OnDragLeave();
  248. return;
  249. }
  250. /////////////////////////////////////////////////////////////////////////////
  251. // COleDropTarget::COleDropTarget implementation
  252. BEGIN_INTERFACE_MAP(COleDropTarget, CCmdTarget)
  253. INTERFACE_PART(COleDropTarget, IID_IDropTarget, DropTarget)
  254. END_INTERFACE_MAP()
  255. STDMETHODIMP_(ULONG) COleDropTarget::XDropTarget::AddRef()
  256. {
  257. METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
  258. return pThis->ExternalAddRef();
  259. }
  260. STDMETHODIMP_(ULONG) COleDropTarget::XDropTarget::Release()
  261. {
  262. METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
  263. return pThis->ExternalRelease();
  264. }
  265. STDMETHODIMP COleDropTarget::XDropTarget::QueryInterface(
  266. REFIID iid, LPVOID* ppvObj)
  267. {
  268. METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget)
  269. return pThis->ExternalQueryInterface(&iid, ppvObj);
  270. }
  271. // helper to filter out invalid DROPEFFECTs
  272. AFX_STATIC DROPEFFECT AFXAPI
  273. _AfxFilterDropEffect(DROPEFFECT dropEffect, DROPEFFECT dwEffects)
  274. {
  275. // return allowed dropEffect and DROPEFFECT_NONE
  276. if ((dropEffect & dwEffects) != 0)
  277. return dropEffect;
  278. // map common operations (copy/move) to alternates, but give negative
  279. // feedback for DROPEFFECT_LINK.
  280. switch (dropEffect)
  281. {
  282. case DROPEFFECT_COPY:
  283. if (dwEffects & DROPEFFECT_MOVE)
  284. return DROPEFFECT_MOVE;
  285. else if (dwEffects & DROPEFFECT_LINK)
  286. return DROPEFFECT_LINK;
  287. break;
  288. case DROPEFFECT_MOVE:
  289. if (dwEffects & DROPEFFECT_COPY)
  290. return DROPEFFECT_COPY;
  291. else if (dwEffects & DROPEFFECT_LINK)
  292. return DROPEFFECT_LINK;
  293. break;
  294. case DROPEFFECT_LINK:
  295. break;
  296. }
  297. return DROPEFFECT_NONE;
  298. }
  299. STDMETHODIMP COleDropTarget::XDropTarget::DragEnter(THIS_ LPDATAOBJECT lpDataObject,
  300. DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect)
  301. {
  302. METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
  303. ASSERT_VALID(pThis);
  304. ASSERT(pdwEffect != NULL);
  305. ASSERT(lpDataObject != NULL);
  306. SCODE sc = E_UNEXPECTED;
  307. TRY
  308. {
  309. // cache lpDataObject
  310. lpDataObject->AddRef();
  311. RELEASE(pThis->m_lpDataObject);
  312. pThis->m_lpDataObject = lpDataObject;
  313. CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
  314. ASSERT_VALID(pWnd);
  315. CPoint point((int)pt.x, (int)pt.y);
  316. pWnd->ScreenToClient(&point);
  317. // check first for entering scroll area
  318. DROPEFFECT dropEffect = pThis->OnDragScroll(pWnd, dwKeyState, point);
  319. if ((dropEffect & DROPEFFECT_SCROLL) == 0)
  320. {
  321. // funnel through OnDragEnter since not in scroll region
  322. COleDataObject dataObject;
  323. dataObject.Attach(lpDataObject, FALSE);
  324. dropEffect = pThis->OnDragEnter(pWnd, &dataObject, dwKeyState,
  325. point);
  326. }
  327. *pdwEffect = _AfxFilterDropEffect(dropEffect, *pdwEffect);
  328. sc = S_OK;
  329. }
  330. END_TRY
  331. return sc;
  332. }
  333. STDMETHODIMP COleDropTarget::XDropTarget::DragOver(THIS_ DWORD dwKeyState,
  334. POINTL pt, LPDWORD pdwEffect)
  335. {
  336. METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
  337. ASSERT_VALID(pThis);
  338. ASSERT(pdwEffect != NULL);
  339. ASSERT(pThis->m_lpDataObject != NULL);
  340. SCODE sc = E_UNEXPECTED;
  341. TRY
  342. {
  343. CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
  344. ASSERT_VALID(pWnd);
  345. CPoint point((int)pt.x, (int)pt.y);
  346. pWnd->ScreenToClient(&point);
  347. // check first for entering scroll area
  348. DROPEFFECT dropEffect = pThis->OnDragScroll(pWnd, dwKeyState, point);
  349. if ((dropEffect & DROPEFFECT_SCROLL) == 0)
  350. {
  351. // funnel through OnDragOver
  352. COleDataObject dataObject;
  353. dataObject.Attach(pThis->m_lpDataObject, FALSE);
  354. dropEffect = pThis->OnDragOver(pWnd, &dataObject, dwKeyState,
  355. point);
  356. }
  357. *pdwEffect = _AfxFilterDropEffect(dropEffect, *pdwEffect);
  358. sc = S_OK;
  359. }
  360. END_TRY
  361. return sc;
  362. }
  363. STDMETHODIMP COleDropTarget::XDropTarget::DragLeave(THIS)
  364. {
  365. METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
  366. ASSERT_VALID(pThis);
  367. CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
  368. ASSERT_VALID(pWnd);
  369. // cancel drag scrolling
  370. pThis->m_nTimerID = MAKEWORD(-1, -1);
  371. // allow derivative to do own cleanup
  372. COleDataObject dataObject;
  373. dataObject.Attach(pThis->m_lpDataObject, FALSE);
  374. pThis->OnDragLeave(pWnd);
  375. // release cached data object
  376. RELEASE(pThis->m_lpDataObject);
  377. return S_OK;
  378. }
  379. STDMETHODIMP COleDropTarget::XDropTarget::Drop(THIS_ LPDATAOBJECT lpDataObject,
  380. DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect)
  381. {
  382. METHOD_PROLOGUE_EX(COleDropTarget, DropTarget)
  383. ASSERT_VALID(pThis);
  384. ASSERT(pdwEffect != NULL);
  385. ASSERT(lpDataObject != NULL);
  386. SCODE sc = E_UNEXPECTED;
  387. TRY
  388. {
  389. // cancel drag scrolling
  390. pThis->m_nTimerID = MAKEWORD(-1, -1);
  391. // prepare for call to OnDragOver
  392. CWnd* pWnd = CWnd::FromHandle(pThis->m_hWnd);
  393. ASSERT_VALID(pWnd);
  394. COleDataObject dataObject;
  395. dataObject.Attach(lpDataObject, FALSE);
  396. CPoint point((int)pt.x, (int)pt.y);
  397. pWnd->ScreenToClient(&point);
  398. // verify that drop is legal
  399. DROPEFFECT dropEffect = _AfxFilterDropEffect(pThis->OnDragOver(pWnd,
  400. &dataObject, dwKeyState, point), *pdwEffect);
  401. // execute the drop (try OnDropEx then OnDrop for backward compatibility)
  402. DROPEFFECT temp = pThis->OnDropEx(pWnd, &dataObject, dropEffect, *pdwEffect, point);
  403. if (temp != -1)
  404. {
  405. // OnDropEx was implemented, return its drop effect
  406. dropEffect = temp;
  407. }
  408. else if (dropEffect != DROPEFFECT_NONE)
  409. {
  410. // OnDropEx not implemented
  411. if (!pThis->OnDrop(pWnd, &dataObject, dropEffect, point))
  412. dropEffect = DROPEFFECT_NONE;
  413. }
  414. else
  415. {
  416. // drop not accepted, allow cleanup
  417. pThis->OnDragLeave(pWnd);
  418. }
  419. // release potentially cached data object
  420. RELEASE(pThis->m_lpDataObject);
  421. *pdwEffect = dropEffect;
  422. sc = S_OK;
  423. }
  424. END_TRY
  425. return sc;
  426. }
  427. /////////////////////////////////////////////////////////////////////////////
  428. // COleDropTarget diagnostics
  429. #ifdef _DEBUG
  430. void COleDropTarget::AssertValid() const
  431. {
  432. CCmdTarget::AssertValid();
  433. if (m_lpDataObject != NULL)
  434. CWnd::FromHandle(m_hWnd)->AssertValid();
  435. }
  436. void COleDropTarget::Dump(CDumpContext& dc) const
  437. {
  438. CCmdTarget::Dump(dc);
  439. dc << "m_hWnd = " << m_hWnd;
  440. dc << "\nm_lpDataObject = " << m_lpDataObject;
  441. dc << "\nm_nTimerID = " << m_nTimerID;
  442. dc << "\nm_dwLastTick = " << m_dwLastTick;
  443. dc << "\n";
  444. }
  445. #endif
  446. /////////////////////////////////////////////////////////////////////////////