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.

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