Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

555 lines
15 KiB

  1. /***************************************************************************\
  2. *
  3. * File: DragDrop.cpp
  4. *
  5. * Description:
  6. * DragDrop.cpp implements drag and drop operations
  7. *
  8. *
  9. * History:
  10. * 7/31/2000: JStall: Created
  11. *
  12. * Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
  13. *
  14. \***************************************************************************/
  15. #include "stdafx.h"
  16. #include "Ctrl.h"
  17. #include "OldDragDrop.h"
  18. #include <SmObject.h>
  19. static const GUID guidDropTarget = { 0x6a8bb3c8, 0xcbfc, 0x40d1, { 0x98, 0x1e, 0x3f, 0x8a, 0xaf, 0x99, 0x13, 0x7b } }; // {6A8BB3C8-CBFC-40d1-981E-3F8AAF99137B}
  20. /***************************************************************************\
  21. *****************************************************************************
  22. *
  23. * class OldTargetLock
  24. *
  25. *****************************************************************************
  26. \***************************************************************************/
  27. /***************************************************************************\
  28. *
  29. * OldTargetLock::Lock
  30. *
  31. * Lock() prepares for executing inside the Context when being called back
  32. * from OLE's IDropTarget that was registered.
  33. *
  34. \***************************************************************************/
  35. BOOL
  36. OldTargetLock::Lock(
  37. IN OldDropTarget * p, // OldDropTarget being used
  38. OUT DWORD * pdwEffect, // Resulting DROPEFFECT if failure
  39. IN BOOL fAddRef) // Lock DT during use
  40. {
  41. m_fAddRef = fAddRef;
  42. m_punk = static_cast<IUnknown *> (p);
  43. if (m_fAddRef) {
  44. m_punk->AddRef();
  45. }
  46. if (p->m_hgadSubject == NULL) {
  47. if (pdwEffect != NULL) {
  48. *pdwEffect = DROPEFFECT_NONE;
  49. }
  50. return FALSE;
  51. }
  52. return TRUE;
  53. }
  54. /***************************************************************************\
  55. *****************************************************************************
  56. *
  57. * class OldDropTarget
  58. *
  59. * NOTE: With the current design and implementation, OldDropTarget can not be
  60. * "removed" from an object until the object is destroyed. If this needs to
  61. * change, we need to revisit this.
  62. *
  63. *****************************************************************************
  64. \***************************************************************************/
  65. const IID * OldDropTarget::s_rgpIID[] =
  66. {
  67. &__uuidof(IUnknown),
  68. &__uuidof(IDropTarget),
  69. NULL
  70. };
  71. PRID OldDropTarget::s_pridListen = 0;
  72. //
  73. // NOTE: We are calling back directly on the IDropTarget's, so we need to grab
  74. // a read-only lock so that the tree doesn't get smashed.
  75. //
  76. /***************************************************************************\
  77. *
  78. * OldDropTarget::~OldDropTarget
  79. *
  80. * ~OldDropTarget() cleans up resources used by the OldDropTarget.
  81. *
  82. \***************************************************************************/
  83. OldDropTarget::~OldDropTarget()
  84. {
  85. OldTargetLock lt;
  86. lt.Lock(this, NULL, FALSE);
  87. xwDragLeave();
  88. SafeRelease(m_pdoSrc);
  89. OldExtension::Destroy();
  90. }
  91. /***************************************************************************\
  92. *
  93. * OldDropTarget::Build
  94. *
  95. * Build() builds a new OldDropTarget instance. This should only be called for
  96. * a RootGadget that doesn't already have a DT.
  97. *
  98. \***************************************************************************/
  99. HRESULT
  100. OldDropTarget::Build(
  101. IN HGADGET hgadRoot, // RootGadget
  102. IN HWND hwnd, // Containing HWND
  103. OUT OldDropTarget ** ppdt) // Newly created DT
  104. {
  105. AssertMsg(hgadRoot != NULL, "Must have a valid root");
  106. //
  107. // Setup a new OldDropTarget on this Gadget / HWND.
  108. //
  109. if (!GetComManager()->Init(ComManager::sOLE)) {
  110. return E_OUTOFMEMORY;
  111. }
  112. SmObjectT<OldDropTarget, IDropTarget> * pdt = new SmObjectT<OldDropTarget, IDropTarget>;
  113. if (pdt == NULL) {
  114. return E_OUTOFMEMORY;
  115. }
  116. pdt->AddRef();
  117. HRESULT hr = GetComManager()->RegisterDragDrop(hwnd, static_cast<IDropTarget *> (pdt));
  118. if (FAILED(hr)) {
  119. pdt->Release();
  120. return E_OUTOFMEMORY;
  121. }
  122. //CoLockObjectExternal(pdt, TRUE, FALSE);
  123. hr = pdt->Create(hgadRoot, &guidDropTarget, &s_pridListen, OldExtension::oUseExisting);
  124. if ((hr == DU_S_ALREADYEXISTS) || FAILED(hr)) {
  125. GetComManager()->RevokeDragDrop(hwnd);
  126. pdt->Release();
  127. return hr;
  128. }
  129. pdt->m_hwnd = hwnd;
  130. *ppdt = pdt;
  131. return S_OK;
  132. }
  133. /***************************************************************************\
  134. *
  135. * OldDropTarget::DragEnter
  136. *
  137. * DragEnter() is called by OLE when entering the DT.
  138. *
  139. \***************************************************************************/
  140. STDMETHODIMP
  141. OldDropTarget::DragEnter(
  142. IN IDataObject * pdoSrc, // Source data
  143. IN DWORD grfKeyState, // Keyboard modifiers
  144. IN POINTL ptDesktopPxl, // Cursor location on desktop
  145. OUT DWORD * pdwEffect) // Resulting DROPEFFECT
  146. {
  147. if (pdoSrc == NULL) {
  148. return E_INVALIDARG;
  149. }
  150. OldTargetLock tl;
  151. if (!tl.Lock(this, pdwEffect)) {
  152. return S_OK;
  153. }
  154. //
  155. // Cache the DataObject.
  156. //
  157. SafeRelease(m_pdoSrc);
  158. if (pdoSrc != NULL) {
  159. pdoSrc->AddRef();
  160. m_pdoSrc = pdoSrc;
  161. }
  162. m_grfLastKeyState = grfKeyState;
  163. POINT ptClientPxl;
  164. return xwDragScan(ptDesktopPxl, pdwEffect, &ptClientPxl);
  165. }
  166. /***************************************************************************\
  167. *
  168. * OldDropTarget::DragOver
  169. *
  170. * DragOver() is called by OLE during the drag operation to give feedback
  171. * while inside the DT.
  172. *
  173. \***************************************************************************/
  174. STDMETHODIMP
  175. OldDropTarget::DragOver(
  176. IN DWORD grfKeyState, // Keyboard modifiers
  177. IN POINTL ptDesktopPxl, // Cursor location on desktop
  178. OUT DWORD * pdwEffect) // Resulting DROPEFFECT
  179. {
  180. OldTargetLock tl;
  181. if (!tl.Lock(this, pdwEffect)) {
  182. return S_OK;
  183. }
  184. m_grfLastKeyState = grfKeyState;
  185. POINT ptClientPxl;
  186. return xwDragScan(ptDesktopPxl, pdwEffect, &ptClientPxl);
  187. }
  188. /***************************************************************************\
  189. *
  190. * OldDropTarget::DragLeave
  191. *
  192. * DragLeave() is called by OLE when leaving the DT.
  193. *
  194. \***************************************************************************/
  195. STDMETHODIMP
  196. OldDropTarget::DragLeave()
  197. {
  198. OldTargetLock tl;
  199. if (!tl.Lock(this, NULL)) {
  200. return S_OK;
  201. }
  202. xwDragLeave();
  203. SafeRelease(m_pdoSrc);
  204. return S_OK;
  205. }
  206. /***************************************************************************\
  207. *
  208. * OldDropTarget::Drop
  209. *
  210. * Drop() is called by OLE when the user has dropped while inside DT.
  211. *
  212. \***************************************************************************/
  213. STDMETHODIMP
  214. OldDropTarget::Drop(
  215. IN IDataObject * pdoSrc, // Source data
  216. IN DWORD grfKeyState, // Keyboard modifiers
  217. IN POINTL ptDesktopPxl, // Cursor location on desktop
  218. OUT DWORD * pdwEffect) // Resulting DROPEFFECT
  219. {
  220. OldTargetLock tl;
  221. if (!tl.Lock(this, pdwEffect)) {
  222. return S_OK;
  223. }
  224. if (!HasTarget()) {
  225. *pdwEffect = DROPEFFECT_NONE;
  226. return S_OK;
  227. }
  228. m_grfLastKeyState = grfKeyState;
  229. //
  230. // Update to get the latest Gadget information.
  231. //
  232. POINT ptClientPxl;
  233. HRESULT hr = xwDragScan(ptDesktopPxl, pdwEffect, &ptClientPxl);
  234. if (FAILED(hr) || (*pdwEffect == DROPEFFECT_NONE)) {
  235. return hr;
  236. }
  237. AssertMsg(HasTarget(), "Must have a target if UpdateTarget() succeeds");
  238. //
  239. // Now that the state has been updated, execute the actual drop.
  240. //
  241. POINTL ptDrop = { ptClientPxl.x, ptClientPxl.y };
  242. m_pdtCur->Drop(pdoSrc, m_grfLastKeyState, ptDrop, pdwEffect);
  243. xwDragLeave();
  244. SafeRelease(m_pdoSrc);
  245. return S_OK;
  246. }
  247. /***************************************************************************\
  248. *
  249. * OldDropTarget::xwDragScan
  250. *
  251. * xwDragScan() is called from the various IDropTarget methods to process
  252. * a request coming from outside.
  253. *
  254. \***************************************************************************/
  255. HRESULT
  256. OldDropTarget::xwDragScan(
  257. IN POINTL ptDesktopPxl, // Cursor location on desktop
  258. OUT DWORD * pdwEffect, // Resulting DROPEFFECT
  259. OUT POINT * pptClientPxl) // Cursor location in client
  260. {
  261. POINT ptContainerPxl;
  262. RECT rcDesktopPxl;
  263. GetClientRect(m_hwnd, &rcDesktopPxl);
  264. ClientToScreen(m_hwnd, (LPPOINT) &(rcDesktopPxl.left));
  265. ptContainerPxl.x = ptDesktopPxl.x - rcDesktopPxl.left;
  266. ptContainerPxl.y = ptDesktopPxl.y - rcDesktopPxl.top;;
  267. return xwUpdateTarget(ptContainerPxl, pdwEffect, pptClientPxl);
  268. }
  269. /***************************************************************************\
  270. *
  271. * OldDropTarget::xwUpdateTarget
  272. *
  273. * xwUpdateTarget() provides the "worker" of DropTarget, updating
  274. * Enter, Leave, and Over information for the Gadgets in the tree.
  275. *
  276. \***************************************************************************/
  277. HRESULT
  278. OldDropTarget::xwUpdateTarget(
  279. IN POINT ptContainerPxl, // Cursor location in container
  280. OUT DWORD * pdwEffect, // Resulting DROPEFFECT
  281. OUT POINT * pptClientPxl) // Cursor location in client
  282. {
  283. AssertMsg(HasSource(), "Only call when have valid data source");
  284. AssertWritePtr(pdwEffect);
  285. AssertWritePtr(pptClientPxl);
  286. m_ptLastContainerPxl = ptContainerPxl;
  287. //
  288. // Determine the Gadget that is currently at the drop location. We use this
  289. // as a starting point.
  290. //
  291. HGADGET hgadFound = FindGadgetFromPoint(m_hgadSubject, ptContainerPxl, GS_VISIBLE | GS_ENABLED, pptClientPxl);
  292. if (hgadFound == NULL) {
  293. *pdwEffect = DROPEFFECT_NONE;
  294. return S_OK;
  295. }
  296. return xwUpdateTarget(hgadFound, pdwEffect, pptClientPxl);
  297. }
  298. /***************************************************************************\
  299. *
  300. * OldDropTarget::xwUpdateTarget
  301. *
  302. * xwUpdateTarget() provides the "worker" of DropTarget, updating
  303. * Enter, Leave, and Over information for the Gadgets in the tree.
  304. *
  305. \***************************************************************************/
  306. HRESULT
  307. OldDropTarget::xwUpdateTarget(
  308. IN HGADGET hgadFound, // Gadget getting Drop
  309. OUT DWORD * pdwEffect, // Resulting DROPEFFECT
  310. IN POINT * pptClientPxl) // Cursor location in client
  311. {
  312. HRESULT hr = S_OK;
  313. //
  314. // Check if the drop Gadget has changed.
  315. //
  316. if ((hgadFound != NULL) && (hgadFound != m_hgadDrop)) {
  317. //
  318. // Ask the new Gadget if he wants to participate in Drag & Drop.
  319. //
  320. GMSG_QUERYDROPTARGET msg;
  321. ZeroMemory(&msg, sizeof(msg));
  322. msg.cbSize = sizeof(msg);
  323. msg.nMsg = GM_QUERY;
  324. msg.nCode = GQUERY_DROPTARGET;
  325. msg.hgadMsg = hgadFound;
  326. static int s_cSend = 0;
  327. Trace("Send Query: %d to 0x%p\n", s_cSend++, hgadFound);
  328. HRESULT hr = DUserSendEvent(&msg, SGM_FULL);
  329. if (IsHandled(hr)) {
  330. if ((msg.hgadDrop != NULL) && (msg.pdt != NULL)) {
  331. if (msg.hgadDrop != hgadFound) {
  332. //
  333. // The message returned a different to handle the DnD request,
  334. // so we need to re-adjust. We know that this Gadget is enabled
  335. // and visible since it is in our parent chain and we are already
  336. // enabled and visible.
  337. //
  338. #if DBG
  339. BOOL fChain = FALSE;
  340. IsGadgetParentChainStyle(msg.hgadDrop, GS_VISIBLE | GS_ENABLED, &fChain, 0);
  341. if (!fChain) {
  342. Trace("WARNING: DUser: DropTarget: Parent chain for 0x%p is not fully visible and enabled.\n", msg.hgadDrop);
  343. }
  344. #endif
  345. MapGadgetPoints(hgadFound, msg.hgadDrop, pptClientPxl, 1);
  346. }
  347. }
  348. } else {
  349. msg.hgadDrop = NULL;
  350. msg.pdt = NULL;
  351. }
  352. //
  353. // Notify the old Gadget that the Drag operation has left him.
  354. // Update to new state
  355. // Notify the new Gadget that the Drag operation has entered him.
  356. //
  357. if (m_hgadDrop != msg.hgadDrop) {
  358. xwDragLeave();
  359. m_hgadDrop = msg.hgadDrop;
  360. m_pdtCur = msg.pdt;
  361. hr = xwDragEnter(pptClientPxl, pdwEffect);
  362. if (FAILED(hr) || (*pdwEffect == DROPEFFECT_NONE)) {
  363. goto Exit;
  364. }
  365. } else {
  366. SafeRelease(msg.pdt);
  367. *pdwEffect = DROPEFFECT_NONE;
  368. }
  369. }
  370. //
  371. // Update the DropTarget
  372. //
  373. if (HasTarget()) {
  374. POINTL ptDrop = { pptClientPxl->x, pptClientPxl->y };
  375. hr = m_pdtCur->DragOver(m_grfLastKeyState, ptDrop, pdwEffect);
  376. }
  377. Exit:
  378. AssertMsg(FAILED(hr) ||
  379. ((*pdwEffect == DROPEFFECT_NONE) && !HasTarget()) ||
  380. HasTarget(),
  381. "Check valid return state");
  382. return hr;
  383. }
  384. /***************************************************************************\
  385. *
  386. * OldDropTarget::xwDragEnter
  387. *
  388. * xwDragEnter() is called when entering a new Gadget during a DnD operation.
  389. *
  390. \***************************************************************************/
  391. HRESULT
  392. OldDropTarget::xwDragEnter(
  393. IN OUT POINT * pptClientPxl, // Client location (updated)
  394. OUT DWORD * pdwEffect) // Resulting DROPEFFECT
  395. {
  396. AssertMsg(HasSource(), "Only call when have valid data source");
  397. //
  398. // Notify the new Gadget that the drop has entered him.
  399. //
  400. if (HasTarget()) {
  401. POINTL ptDrop = { pptClientPxl->x, pptClientPxl->y };
  402. HRESULT hr = m_pdtCur->DragEnter(m_pdoSrc, m_grfLastKeyState, ptDrop, pdwEffect);
  403. if (FAILED(hr)) {
  404. return hr;
  405. }
  406. } else {
  407. *pdwEffect = DROPEFFECT_NONE;
  408. }
  409. return S_OK;
  410. }
  411. /***************************************************************************\
  412. *
  413. * OldDropTarget::xwDragLeave
  414. *
  415. * xwDragLeave() is called when leaving a Gadget during a DnD operation.
  416. *
  417. \***************************************************************************/
  418. void
  419. OldDropTarget::xwDragLeave()
  420. {
  421. if (HasTarget()) {
  422. m_pdtCur->DragLeave();
  423. m_pdtCur->Release();
  424. m_pdtCur = NULL;
  425. m_hgadDrop = NULL;
  426. }
  427. }
  428. //------------------------------------------------------------------------------
  429. void
  430. OldDropTarget::OnDestroyListener()
  431. {
  432. Release();
  433. }
  434. //------------------------------------------------------------------------------
  435. void
  436. OldDropTarget::OnDestroySubject()
  437. {
  438. if (IsWindow(m_hwnd)) {
  439. GetComManager()->RevokeDragDrop(m_hwnd);
  440. }
  441. //CoLockObjectExternal(pdt, FALSE, TRUE);
  442. OldExtension::DeleteHandle();
  443. }