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.

2538 lines
72 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: drag.cpp
  7. //
  8. // Contents: Api's for doing drag'n'drop
  9. //
  10. // Classes: CPoint
  11. // CDragOperation
  12. // CDropTarget
  13. //
  14. // History: dd-mmm-yy Author Comment
  15. // 08-Nov-94 alexgo converted to PrivDragDrop rpc
  16. // for Drag Drop protocol
  17. // 20-Oct-94 alexgo added Win3.1 style drag drop
  18. // for Chicago/NT shell
  19. // 30-Sep-94 ricksa Drag/Drop optimization.
  20. // 18-Jul-94 ricksa made cursors work in shared WOW
  21. // 21-Apr-94 ricksa made drag/drop handle WM_CANCELMODE
  22. // 04-Apr-94 ricksa rewrote DoDragDrop loop
  23. // 11-Jan-94 alexgo added VDATEHEAP to every function
  24. // 29-Dec-93 alexgo converted to RPC alogirithm for
  25. // getting IDropTarget, etc.
  26. // 06-Dec-93 alexgo commented, formatted
  27. // 93/94 Johann Posch (JohannP) created Drag/Drop for Ole 16 bit
  28. //
  29. // Notes:
  30. //
  31. // RPC Drag Drop algorithm:
  32. //
  33. // During a drag drop operation, the user is moving the mouse around
  34. // the screen, passing over many windows. For each window the mouse
  35. // is over, we need to determine if the window is a drop target.
  36. // If it is, then we remote the IDropTarget interface to the DropSource
  37. // so that the correct visual feedbacks can be given.
  38. //
  39. // To accomplish this, RegisterDragDrop adds two properties to the
  40. // drop target window: a public property, EndPoint ID (provided to
  41. // us by compobj), and a private property (available only to the calling
  42. // process), the IDropTarget pointer.
  43. //
  44. // During the DoDragDrop loop, we ask compobj to test each window for
  45. // the EndpointID property. If it is there, compobj (via
  46. // GetInterfaceFromWindowProp), then we will rpc to the drop target
  47. // process, get the IDropTarget pointer and marshal it back to the
  48. // drop source process. We also install a custom message filter to
  49. // ensure that messages (particularly mouse move messages) are handled
  50. // correctly.
  51. //
  52. // RevokeDragDrop simply removes the above mentioned properties from
  53. // the window handle.
  54. //
  55. // Because in Win32, you can always switch windows and mouse capture
  56. // depends on having the mouse button down, drag/drop processing
  57. // is changed slightly. Whenever, the user does an operation that
  58. // would switch windows, the clipboard window that we use for capture
  59. // will get a WM_CANCELMODE. It will notify the drag operation and
  60. // the drag operation will proceed as if the user aborted the operation.
  61. //
  62. //
  63. // Win 3.1 DragDrop algorithm:
  64. //
  65. // Win3.1 apps can register a window as a drop target via DragAcceptFiles.
  66. // This API sets the WS_EX_ACCEPTFILES bit in the window style.
  67. //
  68. // In Win3.1, these apps would get a WM_DROPFILES message when
  69. // files where dropped on them. An hglobal with the filenames is
  70. // sent in the wparam of WM_DROPFILES.
  71. //
  72. // In Chicago and NT3.5, CF_HDROP is a new clipboard format that is
  73. // identical to the data sent in WM_DROPFILES. If we see this format
  74. // available in a data object passed to DoDragDrop, then we enter
  75. // into our Win31 compatibility mode (which affects finding a drop
  76. // target).
  77. //
  78. // When finding a drop target for a given window, we check to
  79. // see if a window in the hierarchy is registered as a Win31 drop
  80. // target. If so, then we create a wrapper drop target. This wrapper
  81. // drop target will forward calls to the real drop target (if available).
  82. //
  83. // With Win3.1 drag drop, we can do a COPY. If the OLE target indicates
  84. // that no OLE drop can be performed (by returning DROPEFFECT_NONE),
  85. // then we substitute in DROPEFFECT_COPY.
  86. //
  87. // On Drop, if the OLE target chooses not to accept the drop, then
  88. // we will post the window a WM_DROPFILES message with the hglobal
  89. // obtained from IDataObject::GetData(CF_HDROP).
  90. //
  91. //--------------------------------------------------------------------------
  92. #include <le2int.h>
  93. #pragma SEG(drag)
  94. #include <getif.hxx>
  95. #include <dragopt.h>
  96. #include <resource.h>
  97. #include "enumgen.h"
  98. #include "clipbrd.h"
  99. #include "drag.h"
  100. NAME_SEG(Drag)
  101. ASSERTDATA
  102. ATOM g_aEndPointAtom;
  103. // DROPFILES is the structure of data contained in the CF_HDROP format.
  104. // However, this is private to the shell, so it is not declared in any
  105. // header files.
  106. typedef struct _DROPFILES {
  107. DWORD pFiles; // offset of file list
  108. POINTL pt; // drop point (client coords)
  109. DWORD fNC; // is it on NonClient area
  110. // and pt is in screen coords
  111. DWORD fWide; // WIDE character switch
  112. } DROPFILES, FAR * LPDROPFILES;
  113. #define WM_NCMOUSEFIRST 0x00A0
  114. #define WM_NCMOUSELAST 0x00A9
  115. // From ido.cpp to create shared memory formats
  116. HANDLE CreateSharedDragFormats(IDataObject *pIDataObject);
  117. #define VK_ALT VK_MENU
  118. static const struct {
  119. int keyCode;
  120. WPARAM keyFlag;
  121. } vKeyMap [] = {
  122. { VK_LBUTTON, MK_LBUTTON },
  123. { VK_RBUTTON, MK_RBUTTON },
  124. { VK_MBUTTON, MK_MBUTTON },
  125. { VK_ALT , MK_ALT },
  126. { VK_SHIFT , MK_SHIFT },
  127. { VK_CONTROL, MK_CONTROL }
  128. };
  129. // This is the default cursor object for 32 bit apps. Only one such object
  130. // is needed for 32 bit apps. 16 bit apps need one per shared WOW application
  131. // that is running.
  132. CDragDefaultCursors *cddcDefault32 = NULL;
  133. extern ATOM g_aDropTarget;
  134. extern ATOM g_aDropTargetMarshalHwnd;
  135. //+-------------------------------------------------------------------------
  136. //
  137. // Member: DragDropProcessUninitialize
  138. //
  139. // Synopsis: Does any Unitialization necessary at OleUninitialize time.
  140. // for the last Unitialize for the Process
  141. //
  142. // Returns: none
  143. //
  144. // Algorithm:
  145. // History: dd-mmm-yy Author Comment
  146. // 18-Jul-94 rogerg Created
  147. //
  148. // Note: We need a per thread default cursor object in WOW because
  149. // of the clean up that WOW does. For 32 bit apps, we just use
  150. // one for the entire process.
  151. //
  152. //--------------------------------------------------------------------------
  153. void DragDropProcessUninitialize(void)
  154. {
  155. if (NULL != cddcDefault32)
  156. {
  157. delete cddcDefault32;
  158. cddcDefault32 = NULL;
  159. }
  160. }
  161. //+-------------------------------------------------------------------------
  162. //
  163. // Member: CDragDefaultCursors::GetDefaultCursorObject, static
  164. //
  165. // Synopsis: Get appropriate pointer to default cursor object
  166. //
  167. // Returns: NULL - error occurred
  168. // ~NULL - pointer to appropriate default cursor table
  169. //
  170. // Algorithm: If we are in a 32 bit app, just get a pointer to the
  171. // single cursor table. In 16 bit, get the per thread cursor
  172. // table. If there is none, then allocate and initialize it.
  173. //
  174. // History: dd-mmm-yy Author Comment
  175. // 18-Jul-94 Ricksa Created
  176. //
  177. // Note: We need a per thread default cursor object in WOW because
  178. // of the clean up that WOW does. For 32 bit apps, we just use
  179. // one for the entire process.
  180. //
  181. //--------------------------------------------------------------------------
  182. CDragDefaultCursors *CDragDefaultCursors::GetDefaultCursorObject(void)
  183. {
  184. if (!IsWOWThread())
  185. {
  186. // If we aren't in WOW, we can use the single common default cursor
  187. // object. We make sure that it is initialized before we use it.
  188. if (NULL == cddcDefault32)
  189. {
  190. cddcDefault32 = new CDragDefaultCursors;
  191. if (cddcDefault32)
  192. {
  193. if (!cddcDefault32->Init())
  194. {
  195. delete cddcDefault32;
  196. cddcDefault32 = NULL;
  197. }
  198. }
  199. }
  200. return cddcDefault32;
  201. }
  202. COleTls tls;
  203. // We are in WOW. Get the cursor object if it has already been allocated
  204. CDragDefaultCursors *pccdc16 = (CDragDefaultCursors *) tls->pDragCursors;
  205. if (pccdc16 == NULL)
  206. {
  207. // No cursor table so allocate it -- Please note that we take advantage
  208. // of the fact that this object has only the default constructor by
  209. // simply allocating it rather than "newing" it. The point is that
  210. // we need to free the memory at thread release time and this happens
  211. // in code that doesn't know about the the object.
  212. pccdc16 = (CDragDefaultCursors *)
  213. PrivMemAlloc(sizeof(CDragDefaultCursors));
  214. if (pccdc16 != NULL)
  215. {
  216. // Successfully allocated so initialize it
  217. if (!pccdc16->Init())
  218. {
  219. PrivMemFree(pccdc16);
  220. return NULL;
  221. }
  222. tls->pDragCursors = pccdc16;
  223. }
  224. }
  225. return pccdc16;
  226. }
  227. //+-------------------------------------------------------------------------
  228. //
  229. // Function: CDragDefaultCursors::Init
  230. //
  231. // Synopsis: Initialize object by loading all the default cursors.
  232. //
  233. // History: dd-mmm-yy Author Comment
  234. // 19-Apr-94 Ricksa Created
  235. //
  236. // Note: We continue the Win16 practice of ignoring possible failure
  237. // cases when loading the cursors although we do put in a
  238. // debug verification that they all loaded.
  239. //
  240. //--------------------------------------------------------------------------
  241. BOOL CDragDefaultCursors::Init(void)
  242. {
  243. // Make sure table is set to NULLs.
  244. memset(&ahcursorDefaults[0][0], 0, sizeof(ahcursorDefaults));
  245. // Load cursors for operation
  246. if ( !(ahcursorDefaults[NO_SCROLL] [NO_DROP]
  247. = LoadCursor (g_hmodOLE2, MAKEINTRESOURCE(CURNONE))) )
  248. return FALSE;
  249. if (!(ahcursorDefaults[NO_SCROLL] [MOVE_DROP] =
  250. LoadCursor (g_hmodOLE2, MAKEINTRESOURCE(CURMOVE))) )
  251. return FALSE;
  252. if (!(ahcursorDefaults[NO_SCROLL] [COPY_DROP] =
  253. LoadCursor (g_hmodOLE2, MAKEINTRESOURCE(CURCOPY))) )
  254. return FALSE;
  255. if (!(ahcursorDefaults[NO_SCROLL] [LINK_DROP] =
  256. LoadCursor(g_hmodOLE2, MAKEINTRESOURCE(CURLINK))) )
  257. return FALSE;
  258. // Load cursors for operation
  259. ahcursorDefaults[SCROLL] [NO_DROP] =
  260. ahcursorDefaults[NO_SCROLL] [NO_DROP];
  261. ahcursorDefaults[SCROLL] [MOVE_DROP] =
  262. ahcursorDefaults[NO_SCROLL] [MOVE_DROP];
  263. ahcursorDefaults[SCROLL] [COPY_DROP] =
  264. ahcursorDefaults[NO_SCROLL] [COPY_DROP];
  265. ahcursorDefaults[SCROLL] [LINK_DROP] =
  266. ahcursorDefaults[NO_SCROLL] [LINK_DROP];
  267. #if DBG == 1
  268. // For debug, verify that cursors were loaded correctly
  269. for (int i = 0; i < 2; i++)
  270. {
  271. for (int j = 0; j < 4; j++)
  272. {
  273. AssertSz((ahcursorDefaults[i] [j] != NULL),
  274. "Drag/Drop cursor initialization failed!");
  275. }
  276. }
  277. #endif // DBG == 1
  278. return TRUE;
  279. }
  280. //+-------------------------------------------------------------------------
  281. //
  282. // Function: CDragDefaultCursors::SetCursor
  283. //
  284. // Synopsis: Set cursor to appropriate value
  285. //
  286. // Algorithm: We use the input effect to calculate the appropriate offset
  287. // into the table for the cursor to use.
  288. //
  289. // History: dd-mmm-yy Author Comment
  290. // 19-Apr-94 Ricksa Created
  291. //
  292. // Note: We use the table approach so we to make consistent behavior
  293. // between scroll and non-scroll cursors.
  294. //
  295. //--------------------------------------------------------------------------
  296. void CDragDefaultCursors::SetCursor(DWORD dwEffect)
  297. {
  298. // Get Scroll index
  299. int iScroll = (dwEffect & DROPEFFECT_SCROLL) ? SCROLL : NO_SCROLL;
  300. int iCursorType = NO_DROP;
  301. if (dwEffect & DROPEFFECT_LINK)
  302. {
  303. iCursorType = LINK_DROP;
  304. }
  305. else if (dwEffect & DROPEFFECT_COPY)
  306. {
  307. iCursorType = COPY_DROP;
  308. }
  309. else if (dwEffect & DROPEFFECT_MOVE)
  310. {
  311. iCursorType = MOVE_DROP;
  312. }
  313. ::SetCursor(ahcursorDefaults[iScroll] [iCursorType]);
  314. }
  315. //
  316. // Drag/Drop Operation Statics
  317. //
  318. LONG CDragOperation::s_wScrollInt = -1;
  319. //+-------------------------------------------------------------------------
  320. //
  321. // Function: GetControlKeysState
  322. //
  323. // Synopsis: queries the current status of the control keys
  324. //
  325. // Arguments: [fAll] -- if true, the just query the keys, not mouse
  326. // buttons too
  327. //
  328. // Returns: the MK flags for each key pressed
  329. //
  330. // Algorithm: Get key state either for all keys and mouse buttons in
  331. // the vKeyMap table or simply for the key portion of the table
  332. // and translate it to the WPARAM form as returned in mouse
  333. // messages.
  334. //
  335. // History: dd-mmm-yy Author Comment
  336. // 06-Dec-93 alexgo 32bit port
  337. //
  338. //--------------------------------------------------------------------------
  339. WORD GetControlKeysState(BOOL fAll)
  340. {
  341. WORD grfKeyState = 0;
  342. int i = (fAll) ? 0 : 3;
  343. for (; i < sizeof(vKeyMap) / sizeof(vKeyMap[0]); i++)
  344. {
  345. if (GetKeyState(vKeyMap[i].keyCode) < 0) // Key down
  346. {
  347. grfKeyState |= vKeyMap[i].keyFlag;
  348. }
  349. }
  350. return grfKeyState;
  351. }
  352. //+-------------------------------------------------------------------------
  353. //
  354. // Function: GetControlKeysStateOfParam
  355. //
  356. // Synopsis: gets the key/button state of wparam (used with mouse messages)
  357. //
  358. // Arguments: [wParam] -- the wParam to parse apart
  359. //
  360. // Returns: the key's set in wParam
  361. //
  362. // Algorithm: First determine if keys we are interested in are set
  363. // in the wParam message. Then go check the state of the
  364. // ALT key and record that in the key state. We then return
  365. // that to the caller.
  366. //
  367. // History: dd-mmm-yy Author Comment
  368. // 06-Dec-93 alexgo 32bit port
  369. //
  370. //--------------------------------------------------------------------------
  371. WORD GetControlKeysStateOfParam(WPARAM wParam)
  372. {
  373. // Check all the buttons we are interested in at once.
  374. WORD grfKeyState = (WORD) wParam
  375. & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_SHIFT | MK_CONTROL);
  376. // get the alt key
  377. if (GetKeyState(VK_ALT) < 0) // Key down
  378. {
  379. grfKeyState |= MK_ALT;
  380. }
  381. return grfKeyState;
  382. }
  383. //+-------------------------------------------------------------------------
  384. //
  385. // Function: IsWin31DropTarget
  386. //
  387. // Synopsis: determines whether the given hwnd is a valid drop target
  388. // for Win31 style drag drop
  389. //
  390. // Effects:
  391. //
  392. // Arguments: [hwnd] -- the window to check
  393. //
  394. // Requires:
  395. //
  396. // Returns: TRUE/
  397. // FALSE
  398. //
  399. // Signals:
  400. //
  401. // Modifies:
  402. //
  403. // Algorithm: checks the WS_EX_ACCEPTFILES style bit. If this bit is
  404. // set and the window is not disabled, then it is a valid
  405. // Win3.1 drop target.
  406. //
  407. // History: dd-mmm-yy Author Comment
  408. // 25-Jan-95 alexgo added check for WS_DISABLED
  409. // 20-Oct-94 alexgo author
  410. //
  411. // Notes:
  412. //
  413. //--------------------------------------------------------------------------
  414. BOOL IsWin31DropTarget( HWND hwnd )
  415. {
  416. LONG exstyle;
  417. exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
  418. if( (exstyle & WS_EX_ACCEPTFILES) )
  419. {
  420. LONG style;
  421. style = GetWindowLong(hwnd, GWL_STYLE);
  422. if( !(style & WS_DISABLED) )
  423. {
  424. return TRUE;
  425. }
  426. }
  427. return FALSE;
  428. }
  429. //+-------------------------------------------------------------------------
  430. //
  431. // Function: UseWin31DragDrop
  432. //
  433. // Synopsis: tests the given data object to see if enough data is offered
  434. // to perform Win3.1 style drag drop
  435. //
  436. // Effects:
  437. //
  438. // Arguments: [pDataObject] -- pointer to the data object
  439. //
  440. // Requires: pdataobj must not be NULL
  441. //
  442. // Returns: TRUE/FALSE
  443. //
  444. // Signals:
  445. //
  446. // Modifies:
  447. //
  448. // Algorithm: does an IDataObject::QueryGetData for CF_HDROP
  449. //
  450. // History: dd-mmm-yy Author Comment
  451. // 30-Oct-94 alexgo author
  452. //
  453. // Notes:
  454. //
  455. //--------------------------------------------------------------------------
  456. BOOL UseWin31DragDrop(IDataObject *pDataObject)
  457. {
  458. FORMATETC formatetc;
  459. INIT_FORETC(formatetc);
  460. formatetc.cfFormat = CF_HDROP;
  461. formatetc.tymed = TYMED_HGLOBAL;
  462. if( pDataObject->QueryGetData(&formatetc) == NOERROR )
  463. {
  464. return TRUE;
  465. }
  466. else
  467. {
  468. return FALSE;
  469. }
  470. }
  471. //+-------------------------------------------------------------------------
  472. //
  473. // Function: IsNCDrop
  474. //
  475. // Synopsis: are we dropping into the non-client area of the window or
  476. // on an iconic window?
  477. //
  478. // Effects: *DOES A SEND MESSAGE*!!!
  479. //
  480. // Arguments: [hwnd] -- the window to ask
  481. // [pt] -- the point in screen coords
  482. //
  483. // Requires:
  484. //
  485. // Returns: TRUE/FALSE (TRUE if in non-client area)
  486. //
  487. // Signals:
  488. //
  489. // Modifies:
  490. //
  491. // Algorithm:
  492. //
  493. // History: dd-mmm-yy Author Comment
  494. // 25-Jan-95 alexgo borrowed from Win95 shell sources
  495. //
  496. // Notes:
  497. //
  498. //--------------------------------------------------------------------------
  499. BOOL IsNCDrop(HWND hwnd, POINT pt)
  500. {
  501. return (!IsIconic(hwnd) &&
  502. HTCLIENT!=SendMessage(hwnd, WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y)));
  503. }
  504. //+-------------------------------------------------------------------------
  505. //
  506. // Member: GetDropTarget
  507. //
  508. // Synopsis: Gets the IDropTarget * from the closest window in the
  509. // hierachy up from the given window (if available, of
  510. // course ;-)
  511. //
  512. // Arguments: [hwndCur] -- the window to the cursor is currently over
  513. // [hwndDropTarget] -- the window that contains a valid DropTarget
  514. //
  515. // Returns: Result of drag enter operation at Target
  516. //
  517. // Algorithm: Loop calling PrivDragDrop until we get a drop target or
  518. // we run out of windows that are parent to the window that
  519. // the mouse is currently on.
  520. //
  521. // If a window in the hierarchy has registered itself for
  522. // Win3.1 drag drop, then we create a drop target wrapper
  523. // (CDropTarget) to handle the Win3.1 protocol. Note
  524. // that a window hierarchy may be both OLE *and* Win3.1
  525. // targets.
  526. //
  527. // History: dd-mmm-yy Author Comment
  528. // 08-Nov-94 alexgo converted to use PrivDragDrop
  529. // 20-Oct-94 alexgo added Win31 drop target support
  530. // 30-Sep-94 ricksa Drag/Drop optimization.
  531. // 21-Jul-94 alexgo removed GetDropTargetFromWindow
  532. // optimization and put that functionality
  533. // in GetInterfaceFromWindowProp (to
  534. // help make clipboard faster).
  535. // 06-Apr-94 Ricksa Modified to call GetDropTargetFromWindow
  536. // to optimize local calls
  537. // 11-Jan-94 alexgo changed name from GetTopStm to
  538. // GetDropTarget, converted to the RPC-style
  539. // drag drop, added a VDATEHEAP macro
  540. // 06-Dec-93 alexgo commented
  541. //
  542. //--------------------------------------------------------------------------
  543. HRESULT CDragOperation::GetDropTarget(HWND hwnd31,HWND hwndDropTarget)
  544. {
  545. IDropTarget *ptarget = NULL;
  546. DDInfo hDDInfo = NULL;
  547. VDATEHEAP();
  548. DDDebugOut((DEB_ITRACE, "%p _IN GetDropTarget ( %x,%x)\n", this, hwnd31,hwndDropTarget));
  549. _pDropTarget = NULL;
  550. HRESULT hr = E_FAIL;
  551. if (hwndDropTarget)
  552. {
  553. HWND hwndClipWindow;
  554. Assert(GetProp(hwndDropTarget, (LPCWSTR)g_aDropTarget));
  555. // If the DropTarget hasn't been marshaled, Marshal it now.
  556. if (hwndClipWindow = (HWND) GetProp(hwndDropTarget,(LPCWSTR) g_aDropTargetMarshalHwnd))
  557. {
  558. SSSendMessage(hwndClipWindow,WM_OLE_CLIPBRD_MARSHALDROPTARGET,0,(LPARAM) hwndDropTarget);
  559. }
  560. hr = PrivDragDrop(hwndDropTarget,
  561. DRAGOP_ENTER,
  562. _DOBuffer,
  563. _pDataObject,
  564. _grfKeyState,
  565. _cpt.GetPOINTL(),
  566. _pdwEffect,
  567. NULL,
  568. &hDDInfo);
  569. if (hr != NOERROR)
  570. {
  571. hwndDropTarget = NULL;
  572. }
  573. }
  574. Assert( (NULL == hwnd31) || IsWin31DropTarget(hwnd31));
  575. if( hwndDropTarget || hwnd31 )
  576. {
  577. ptarget = new CDropTarget(hwnd31, hwndDropTarget, *_pdwEffect, this, hDDInfo);
  578. if( ptarget == NULL )
  579. {
  580. hr = E_OUTOFMEMORY;
  581. }
  582. else
  583. {
  584. hr = NOERROR;
  585. }
  586. // if we have a Win31 drop target AND the OLE drop target returned
  587. // DROPEFFECT_NONE, then we should return DROPEFFECT_COPY
  588. if( hr == NOERROR && *_pdwEffect == DROPEFFECT_NONE && hwnd31 )
  589. {
  590. *_pdwEffect = DROPEFFECT_COPY;
  591. }
  592. _pDropTarget = ptarget;
  593. }
  594. DDDebugOut((DEB_ITRACE, "%p OUT GetDropTarget ( %lx ) [ %p ]\n",
  595. this, hr, _pDropTarget));
  596. return hr;
  597. }
  598. //+-------------------------------------------------------------------------
  599. //
  600. // Function: CDragOperation::CDragOperation
  601. //
  602. // Synopsis: Initialize the object to start the operation
  603. //
  604. // Arguments: [pDataObject] - pointer to data object to drop
  605. // [pDropSource] - pointer to source for drop operation
  606. // [dwOKEffects] - effects allowed in drag operation
  607. // [pdwEffect] - how operation affected source data
  608. // [hr] - whether constructor succeeded
  609. //
  610. // Algorithm: Initialize data in object. Make sure that static data
  611. // is initialized. Wait for first mouse message to begin.
  612. //
  613. // History: dd-mmm-yy Author Comment
  614. // 20-Oct-94 alexgo added support for Win31 drag drop
  615. // 04-Apr-94 Ricksa Created
  616. //
  617. //--------------------------------------------------------------------------
  618. CDragOperation::CDragOperation(
  619. LPDATAOBJECT pDataObject,
  620. LPDROPSOURCE pDropSource,
  621. DWORD dwOKEffects,
  622. DWORD FAR *pdwEffect,
  623. HRESULT& hr)
  624. :
  625. _pDataObject(pDataObject),
  626. _DOBuffer(NULL),
  627. _pDropSource(pDropSource),
  628. _pDropTarget(NULL),
  629. _pRealDropTarget(NULL),
  630. _hFormats(NULL),
  631. _dwOKEffects(dwOKEffects),
  632. _pdwEffect(pdwEffect),
  633. _fEscapePressed(FALSE),
  634. _curOld(GetCursor()),
  635. _hwndLast((HWND) -1),
  636. _grfKeyState(0),
  637. _hrDragResult(S_OK),
  638. _fReleasedCapture(FALSE),
  639. _pcddcDefault(NULL),
  640. _fUseWin31(FALSE)
  641. {
  642. VDATEHEAP();
  643. // Set the default scroll interval
  644. if (s_wScrollInt < 0)
  645. {
  646. InitScrollInt();
  647. }
  648. hr = GetMarshalledInterfaceBuffer(IID_IDataObject, pDataObject,
  649. &_DOBuffer);
  650. if( hr != NOERROR )
  651. {
  652. Assert(NULL == _DOBuffer);
  653. return;
  654. }
  655. // Get appropriate default cursor table object
  656. if ((_pcddcDefault = CDragDefaultCursors::GetDefaultCursorObject()) == NULL)
  657. {
  658. // Some error occurred while we were trying to initialize the
  659. // so return an error. This should be highly unusual.
  660. DDDebugOut((DEB_ERROR,
  661. "CDragDefaultCursors::GetDefaultCursorObject Failed!\n"));
  662. hr = E_FAIL;
  663. return;
  664. }
  665. // We will use the clipboard window to capture the mouse but we
  666. // must have a clipboard window so we make sure it is created
  667. // if it is not already there.
  668. hr = ClipSetCaptureForDrag(this);
  669. if (FAILED(hr))
  670. {
  671. return;
  672. }
  673. _hFormats = CreateSharedDragFormats(pDataObject);
  674. // it's OK for _hFormats to be NULL (indicates an empty or non-existant
  675. // formatetc enumertor
  676. // For following peek
  677. MSG msg;
  678. // Busy wait until a mouse or escape message is in the queue
  679. while (!PeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
  680. {
  681. // Note: all keyboard messages except escape are tossed. This is
  682. // fairly reasonable since the user has to be holding the left
  683. // mouse button down at this point. They can't really be doing
  684. // too much data input one handed.
  685. if ((PeekMessage(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE)
  686. || PeekMessage(&msg, 0, WM_SYSKEYDOWN, WM_SYSKEYDOWN, PM_REMOVE))
  687. && msg.wParam == VK_ESCAPE)
  688. {
  689. _fEscapePressed = TRUE;
  690. break;
  691. }
  692. }
  693. // get mouse pos and key state
  694. if (!_fEscapePressed)
  695. {
  696. _cpt.Set(msg.pt.x, msg.pt.y);
  697. _grfKeyState = GetControlKeysStateOfParam(msg.wParam);
  698. }
  699. else
  700. {
  701. // We ask the cursor for its position since we didn't get a
  702. // position from the mouse.
  703. GetCursorPos(_cpt.GetAddressOfPOINT());
  704. _grfKeyState = GetControlKeysState(TRUE);
  705. }
  706. // Check to see if we need to do Win3.1 style drag drop.
  707. // If we do, then set a flag so we can construct a fake drop target as
  708. // needed
  709. if( UseWin31DragDrop(pDataObject) )
  710. {
  711. _fUseWin31 = TRUE;
  712. }
  713. }
  714. //+-------------------------------------------------------------------------
  715. //
  716. // Function: ~CDragOperation
  717. //
  718. // Synopsis: Clean up object
  719. //
  720. // Algorithm: Release mouse capture. Restore ole cursor. Remove enum
  721. // formats.
  722. //
  723. // History: dd-mmm-yy Author Comment
  724. // 04-Apr-94 Ricksa Created
  725. //
  726. //--------------------------------------------------------------------------
  727. CDragOperation::~CDragOperation(void)
  728. {
  729. VDATEHEAP();
  730. AssertSz((_pDropTarget == NULL), "CDragOperation::~CDragOperation");
  731. // Stop the mouse capture
  732. ReleaseCapture();
  733. // Restore the cursor if it got changed
  734. SetCursor(_curOld);
  735. // Close the handle to the shared memory
  736. if (_hFormats)
  737. {
  738. CloseHandle(_hFormats);
  739. _hFormats = NULL;
  740. }
  741. if( _DOBuffer )
  742. {
  743. ReleaseMarshalledInterfaceBuffer(_DOBuffer);
  744. }
  745. }
  746. //+-------------------------------------------------------------------------
  747. //
  748. // Function: CDragOperation::InitScrollInt
  749. //
  750. // Synopsis: Initialize the scroll interval
  751. //
  752. // Algorithm: Look in profile for defined interval. If none set, then
  753. // default to zero.
  754. //
  755. // History: dd-mmm-yy Author Comment
  756. // 04-Apr-94 Ricksa Created
  757. //
  758. //--------------------------------------------------------------------------
  759. void CDragOperation::InitScrollInt(void)
  760. {
  761. DWORD dw;
  762. OLECHAR szBuffer[20];
  763. s_wScrollInt = DD_DEFSCROLLDELAY;
  764. dw = sizeof(szBuffer);
  765. if (ERROR_SUCCESS == RegQueryValueEx(HKEY_CURRENT_USER,
  766. OLESTR("Control Panel\\Mouse\\DragScrollDelay"),
  767. NULL,
  768. NULL,
  769. (LPBYTE)szBuffer,
  770. &dw))
  771. {
  772. s_wScrollInt = wcstol(szBuffer, NULL, 0);
  773. }
  774. }
  775. //+-------------------------------------------------------------------------
  776. //
  777. // Function: CDragOperation::UpdateTarget
  778. //
  779. // Synopsis: Update the target window based on mouse location
  780. //
  781. // Returns: TRUE - continue drag operation
  782. // FALSE - error or time to drop
  783. //
  784. // Algorithm: First, we query the source to see if it wants to continue
  785. // with the drop. If so, we get current window for mouse. If
  786. // it is different than the previous window check to see whether
  787. // the targets are different. If they are different, then notify
  788. // the current target that we are leaving and then notify the
  789. // new target that we have arrived.
  790. //
  791. // History: dd-mmm-yy Author Comment
  792. // 04-Apr-94 Ricksa Created
  793. // 10-Jul-94 AlexT Allow same IDropTarget on different HWNDs
  794. //
  795. //--------------------------------------------------------------------------
  796. BOOL CDragOperation::UpdateTarget(void)
  797. {
  798. VDATEHEAP();
  799. DDDebugOut((DEB_ITRACE, "%p _IN CDragOperation::UpdateTarget ( )\n", this));
  800. // Assume this operation will continue the drag drop
  801. BOOL fResult = TRUE;
  802. HRESULT hr;
  803. LPDROPTARGET lpCurDropTarget = NULL,
  804. lpOldDropTarget = NULL;
  805. HWND hWndTemp = NULL;
  806. HWND hwndCur = WindowFromPoint(_cpt.GetPOINT());
  807. // Query continue can return telling us one of four things:
  808. // (1) Keep going (S_OK), (2) Drop operation should occur
  809. // (DRAGDROP_S_DROP), (3) Drop operation is canceled
  810. // (DRAGDROP_S_CANCEL) or (4) An unexpected error has occurred.
  811. HRESULT hrQuery = _pDropSource->QueryContinueDrag(_fEscapePressed,
  812. _grfKeyState);
  813. if (FAILED(hrQuery) || (hrQuery == ResultFromScode(DRAGDROP_S_CANCEL)))
  814. {
  815. // Unexpected error or the operation has been cancelled so give up.
  816. _hrDragResult = hrQuery;
  817. fResult = FALSE;
  818. goto UpdateTarget_exit;
  819. }
  820. // walk up the window list to find the actual pointer values for the current
  821. // and old IDropTarget interfaces
  822. if (hwndCur != _hwndLast)
  823. {
  824. hWndTemp = _hwndLast;
  825. BOOL fChangedWin31 = FALSE;
  826. HWND hWndOldDrop = NULL;
  827. HWND hWndNewDrop = NULL;
  828. HWND hWndWin31Drop = NULL;
  829. LPDROPTARGET lpRealDropTarget = NULL;
  830. HANDLE hTemp = NULL;
  831. DWORD dwCurrentProcessId = 0;
  832. if (hWndTemp != (HWND)-1)
  833. GetWindowThreadProcessId(hWndTemp, &dwCurrentProcessId);
  834. DWORD dwTempProcessID = dwCurrentProcessId;
  835. while (hWndTemp && !lpRealDropTarget && hWndTemp != (HWND)-1 && dwTempProcessID == dwCurrentProcessId)
  836. {
  837. if (lpRealDropTarget = (IDropTarget *)GetProp(hWndTemp, (LPCWSTR)g_aDropTarget))
  838. {
  839. hWndOldDrop = hWndTemp;
  840. }
  841. hWndTemp = GetParent(hWndTemp);
  842. if (hWndTemp)
  843. {
  844. GetWindowThreadProcessId(hWndTemp, &dwTempProcessID);
  845. }
  846. }
  847. hWndTemp = hwndCur;
  848. if (hWndTemp != (HWND)-1)
  849. GetWindowThreadProcessId(hWndTemp, &dwCurrentProcessId);
  850. dwTempProcessID = dwCurrentProcessId;
  851. while (hWndTemp && dwTempProcessID == dwCurrentProcessId)
  852. {
  853. // If we haven't found the DropTarget yet, check this window.
  854. if (!lpCurDropTarget)
  855. {
  856. if (lpCurDropTarget = (IDropTarget *)GetProp(hWndTemp, (LPCWSTR)g_aDropTarget))
  857. {
  858. hWndNewDrop = hWndTemp;
  859. }
  860. }
  861. // if the current window is a win31 drop target, update the win31 window
  862. // handle in our DropTarget Class. NOTE: Beware, this code relies on the
  863. // fact that we can party on the CDropTarget Class directly, knowing that
  864. // the class is reconstructed below as a result of the GetDropTarget()
  865. // when the real IDropTarget ptrs change.
  866. if (!fChangedWin31 &&
  867. IsWin31DropTarget(hWndTemp) &&
  868. _fUseWin31)
  869. {
  870. fChangedWin31 = TRUE;
  871. hWndWin31Drop = hWndTemp;
  872. if (_pDropTarget)
  873. {
  874. ((CDropTarget*)_pDropTarget)->_hwnd31 = hWndTemp;
  875. }
  876. }
  877. // if have a droptarget, and handle Win31 break.
  878. if (lpCurDropTarget && (!_fUseWin31 || fChangedWin31))
  879. {
  880. break;
  881. }
  882. hWndTemp = GetParent(hWndTemp);
  883. if (hWndTemp)
  884. {
  885. GetWindowThreadProcessId(hWndTemp, &dwTempProcessID);
  886. }
  887. }
  888. // only update the drop target if the target has actually changed.
  889. // HACK ALERT: We must explicitly check _hwndLast for -1 because Excel does not
  890. // use OLE drag drop internally. When the cursor is moved outside the Overlapped
  891. // Excel window, DoDragDrop is called. At this point _pRealDropTarget == NULL
  892. // and lpCurDropTarget == NULL, and the no-smoking cursor does not appear.
  893. // the _pRealDropTarget==NULL relies on the fact that lpCurDropTarget==NULL. This
  894. // is true because the first case would short-circuit the rest of the condition
  895. // otherwise
  896. if ( (lpCurDropTarget != _pRealDropTarget) ||
  897. (_hwndLast == (HWND)-1) ||
  898. (hWndNewDrop != hWndOldDrop) ||
  899. (_pRealDropTarget == NULL))
  900. {
  901. DDDebugOut((DEB_ITRACE, "%p lpCurDropTarget != lpOldDropTarget\n", this));
  902. // The window that we are working on has changed
  903. _hwndLast = hwndCur;
  904. _pRealDropTarget = lpCurDropTarget;
  905. //Allow the owner of the window to take foreground if it tries to.
  906. if (dwCurrentProcessId)
  907. AllowSetForegroundWindow(dwCurrentProcessId);
  908. // Assume that neither current or previous window are drop aware
  909. BOOL fCurAndLastNotDropAware = TRUE;
  910. if (_pDropTarget != NULL)
  911. {
  912. // There was a previous drop target
  913. // Last window was drag/drop aware
  914. fCurAndLastNotDropAware = FALSE;
  915. // Tell the drop target we are leaving & release it
  916. _pDropTarget->DragLeave();
  917. _pDropTarget->Release();
  918. _pDropTarget = NULL;
  919. }
  920. // Set up effects for query of target
  921. *_pdwEffect = _dwOKEffects;
  922. hr = GetDropTarget(hWndWin31Drop,hWndNewDrop);
  923. if (_pDropTarget != NULL)
  924. {
  925. // This window is drop awarre
  926. fCurAndLastNotDropAware = FALSE;
  927. // Errors from this call are ignored. We interpret them
  928. // as the drop being disallowed. Since we don't really
  929. // use this information here but in the DragOver call
  930. // we make shortly, we just use this call to notify
  931. // the application that we are beginning a drag operation.
  932. if (!HandleFeedBack(hr))
  933. {
  934. goto UpdateTarget_exit;
  935. }
  936. }
  937. else
  938. {
  939. // Tell the source that nothing happened
  940. // only use DROPEFFECT_NONE if there is no new drop target.
  941. hr = _pDropSource->GiveFeedback(*_pdwEffect = DROPEFFECT_NONE);
  942. if (hr != NOERROR)
  943. {
  944. if (DRAGDROP_S_USEDEFAULTCURSORS == GetScode(hr))
  945. {
  946. _pcddcDefault->SetCursorNone();
  947. }
  948. else
  949. {
  950. // Unexpected error -- we will give up drag/drop.
  951. DDDebugOut((DEB_ERROR,
  952. "CDragOperation::UpdateTarget 1st GiveFeedback FAILED %x\n",
  953. hr));
  954. _hrDragResult = hr;
  955. fResult = FALSE;
  956. goto UpdateTarget_exit;
  957. }
  958. }
  959. }
  960. if (fCurAndLastNotDropAware)
  961. {
  962. // Neither new or old window know about drag/drop so set
  963. // cursor accordingly.
  964. _pcddcDefault->SetCursorNone();
  965. }
  966. }
  967. else
  968. {
  969. // The window that we are working on has changed
  970. _hwndLast = hwndCur;
  971. }
  972. }
  973. if (hrQuery != NOERROR)
  974. {
  975. // Query asked for a drop
  976. fResult = FALSE;
  977. _hrDragResult = hrQuery;
  978. }
  979. UpdateTarget_exit:
  980. DDDebugOut((DEB_ITRACE, "%p OUT CDragOperation::UpdateTarget ( %lx )\n",
  981. this, fResult));
  982. return fResult;
  983. }
  984. //+-------------------------------------------------------------------------
  985. //
  986. // Function: CDragOperation::HandleFeedBack
  987. //
  988. // Synopsis: Handle feedback and update of cursor
  989. //
  990. // Arguments: [hr] - hresult from previous operation on drop target.
  991. //
  992. // Returns: TRUE - continue drag operation
  993. // FALSE - error
  994. //
  995. // Algorithm: If previous operation on the target failed, map this to a
  996. // disallowed drop. Then ask the source for feedback. If it
  997. // so requests, then update the cursor. If an unexpected
  998. // error occurs, let caller know that loop should break.
  999. //
  1000. // History: dd-mmm-yy Author Comment
  1001. // 19-Apr-94 Ricksa Created
  1002. //
  1003. //--------------------------------------------------------------------------
  1004. BOOL CDragOperation::HandleFeedBack(HRESULT hr)
  1005. {
  1006. VDATEHEAP();
  1007. DDDebugOut((DEB_ITRACE, "%p _IN CDragOperation::HandleFeedBack ( %x )\n",
  1008. this, hr));
  1009. BOOL fResult = TRUE;
  1010. if (hr != NOERROR)
  1011. {
  1012. // target not responding for some reason; treat
  1013. // as if drop not possible, but don't preserve
  1014. // the reason why.
  1015. *_pdwEffect = DROPEFFECT_NONE;
  1016. }
  1017. // If bogus return from drag over, then make sure results are appropriate.
  1018. // However, if we are in a WOW we need to do things a little differently
  1019. // to maintain complete compatability with Win 3.1. In 16-bit OLE 2.0,
  1020. // the *_pdwEffect value is not changed when displaying feedback (i.e.,
  1021. // the result of the & is not stored back into *_pdwEffect in Win 3.1...
  1022. // in straight NT we do). Not storing the results back into *_pdwEffect
  1023. // when InWow() is a hack specifically for Visio, and even more
  1024. // specifically, for dragging from Visio's palette of "items" to an
  1025. // Excel spreadsheet.
  1026. if (IsWOWThread())
  1027. {
  1028. hr = _pDropSource->GiveFeedback( *_pdwEffect & (_dwOKEffects | DROPEFFECT_SCROLL));
  1029. }
  1030. else
  1031. {
  1032. *_pdwEffect &= (_dwOKEffects | DROPEFFECT_SCROLL);
  1033. hr = _pDropSource->GiveFeedback(*_pdwEffect);
  1034. }
  1035. if(hr != NOERROR)
  1036. {
  1037. // Either we want to change the cursor or some unexpected
  1038. // error has occurred.
  1039. if (DRAGDROP_S_USEDEFAULTCURSORS == GetScode(hr))
  1040. {
  1041. _pcddcDefault->SetCursor(*_pdwEffect);
  1042. }
  1043. else
  1044. {
  1045. DDDebugOut((DEB_ERROR,
  1046. "CDragOperation::HandleFeedBack Feedback FAILED %x\n", hr));
  1047. fResult = FALSE;
  1048. _hrDragResult = hr;
  1049. }
  1050. }
  1051. DDDebugOut((DEB_ITRACE, "%p OUT CDragOperation::HandleFeedBack ( %lx )\n",
  1052. this, fResult));
  1053. return fResult;
  1054. }
  1055. //+-------------------------------------------------------------------------
  1056. //
  1057. // Function: CDragOperation::DragOver
  1058. //
  1059. // Synopsis: Tell the target we are dragging over and process the result
  1060. //
  1061. // Returns: TRUE - continue drag operation
  1062. // FALSE - error or time to drop
  1063. //
  1064. // Algorithm: Call the target's drag over if there is one and then
  1065. // get the sources feedback to update the cursor accordingly.
  1066. //
  1067. // History: dd-mmm-yy Author Comment
  1068. // 04-Apr-94 Ricksa Created
  1069. //
  1070. //--------------------------------------------------------------------------
  1071. BOOL CDragOperation::DragOver(void)
  1072. {
  1073. VDATEHEAP();
  1074. DDDebugOut((DEB_ITRACE, "%p _IN CDragOperation::DragOver ( )\n", this));
  1075. // Default the result of the function to continue the loop for
  1076. // drag and drop.
  1077. BOOL fResult = TRUE;
  1078. // Local holder for errors.
  1079. HRESULT hr;
  1080. if (_pDropTarget != NULL)
  1081. {
  1082. // Keep effect in a local variable to save indirections
  1083. // in this routine.
  1084. *_pdwEffect = _dwOKEffects;
  1085. hr = _pDropTarget->DragOver(_grfKeyState, _cpt.GetPOINTL(), _pdwEffect);
  1086. // Get feedback from source & update cursor if necessary
  1087. fResult = HandleFeedBack(hr);
  1088. }
  1089. DDDebugOut((DEB_ITRACE, "%p OUT CDragOperation::DragOver ( %lx )\n",
  1090. this, fResult));
  1091. return fResult;
  1092. }
  1093. //+-------------------------------------------------------------------------
  1094. //
  1095. // Function: CDragOperation::HandleMessages
  1096. //
  1097. // Synopsis: Handle windows messages
  1098. //
  1099. // Returns: TRUE - continue drag operation
  1100. // FALSE - error or time to drop
  1101. //
  1102. // Algorithm: Check for any windows message. If the message is a mouse
  1103. // message then record the new position of the mouse. If it
  1104. // is a key message, the record whether escape has been pushed.
  1105. // If this is any other message, then dispatch it. Repeat this
  1106. // process until the scroll interval has been exceeded.
  1107. //
  1108. // History: dd-mmm-yy Author Comment
  1109. // 04-Apr-94 Ricksa Created
  1110. //
  1111. //--------------------------------------------------------------------------
  1112. BOOL CDragOperation::HandleMessages(void)
  1113. {
  1114. VDATEHEAP();
  1115. DDDebugOut((DEB_ITRACE, "%p _IN CDragOperation::HandleMessages ( )\n",
  1116. this));
  1117. // Message buffer
  1118. MSG msg;
  1119. // Default result of function to continue
  1120. BOOL fResult = TRUE;
  1121. // Capture all messages (i.e. modal loop).
  1122. // Process all input messages, dispatch other messages
  1123. //
  1124. // Note:we must NOT loop here until a hardware message comes in
  1125. // scrolling will not work.
  1126. // * yielding is important since other apps need to run
  1127. // * look for mouse messages first since these are the most
  1128. // impotant
  1129. // Flag for whether we peeked a message
  1130. BOOL fMsg;
  1131. //
  1132. // Sundown - The SetTimer return value can be truncated.
  1133. // We are passing NULL as HWND and Win32 will returned
  1134. // a value not greater than 4GB...
  1135. // If a check is required we could consider a temporary
  1136. // UINT_PTR value and do an ASSERT on its value...
  1137. //
  1138. UINT uTimer = (UINT)SetTimer(NULL, 0, s_wScrollInt, NULL);
  1139. do
  1140. {
  1141. fMsg = FALSE;
  1142. // Note: the order of peek is important - further messages can show up
  1143. // in the last peek
  1144. // If we looked for mouse messages first, we might never pick up
  1145. // WM_QUIT or keyboard messages (because by the time we finished
  1146. // processing the mouse message another might be on the queue).
  1147. // So, we check for WM_QUIT and keyboard messages first.
  1148. if (PeekMessage(&msg, 0, WM_QUIT, WM_QUIT, PM_REMOVE | PM_NOYIELD) ||
  1149. PeekMessage(&msg, 0, WM_KEYFIRST, WM_KEYLAST,
  1150. PM_REMOVE | PM_NOYIELD) ||
  1151. PeekMessage(&msg, 0, WM_SYSKEYDOWN, WM_SYSKEYUP,
  1152. PM_REMOVE | PM_NOYIELD) ||
  1153. PeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) ||
  1154. PeekMessage(&msg, 0, WM_NCMOUSEFIRST, WM_NCMOUSELAST,
  1155. PM_REMOVE | PM_NOYIELD) ||
  1156. PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD))
  1157. {
  1158. fMsg = TRUE;
  1159. if (msg.message == WM_QUIT)
  1160. {
  1161. // Quit message so we are done.
  1162. PostQuitMessage((int) msg.wParam);
  1163. // We are going exiting so the error doesn't matter too much
  1164. _hrDragResult = ResultFromScode(E_UNSPEC);
  1165. // Make sure we break out of the loop
  1166. fResult = FALSE;
  1167. }
  1168. else if ((msg.message >= WM_KEYFIRST &&
  1169. msg.message <= WM_KEYLAST) ||
  1170. (msg.message >= WM_SYSKEYDOWN &&
  1171. msg.message <= WM_SYSKEYUP))
  1172. {
  1173. // Pull all keyboard messages from the queue - this keeps
  1174. // the keyboard state in sync with the user's actions
  1175. // We use a do/while so that we process the message we've
  1176. // already peeked.
  1177. do
  1178. {
  1179. // We only really pay attention to the escape key and dump
  1180. // any other key board messages.
  1181. if ((msg.message == WM_KEYDOWN
  1182. || msg.message == WM_SYSKEYDOWN)
  1183. && msg.wParam == VK_ESCAPE)
  1184. {
  1185. // Esc pressed: Cancel
  1186. _fEscapePressed = TRUE;
  1187. }
  1188. }
  1189. while (PeekMessage(&msg, 0, WM_KEYFIRST, WM_KEYLAST,
  1190. PM_REMOVE | PM_NOYIELD) ||
  1191. PeekMessage(&msg, 0, WM_SYSKEYDOWN, WM_SYSKEYUP,
  1192. PM_REMOVE | PM_NOYIELD));
  1193. DWORD grfKeyState; // temp variable for key state
  1194. // get the key state don't change the button states!!
  1195. grfKeyState = GetControlKeysState(FALSE) |
  1196. (_grfKeyState &
  1197. (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON));
  1198. // if the keyboard state is unchanged, then don't exit
  1199. // this loop (as that will result in DragOver being called).
  1200. // If we call DragOver for each keyboard message, then
  1201. // performance is unacceptably slow.
  1202. if ((grfKeyState == _grfKeyState) && !_fEscapePressed)
  1203. {
  1204. fMsg = FALSE;
  1205. }
  1206. else
  1207. {
  1208. DDDebugOut((DEB_ITRACE, "Updating key state\n"));
  1209. _grfKeyState = grfKeyState;
  1210. }
  1211. }
  1212. else if (msg.message >= WM_MOUSEFIRST &&
  1213. msg.message <= WM_MOUSELAST)
  1214. {
  1215. // we may not have the focus (e.g. if we are the Chicago
  1216. // shell). Therefore, we won't ever get any WM_KEYDOWN
  1217. // messages. Double check the esc key status here
  1218. if( GetKeyState(VK_ESCAPE) < 0 )
  1219. {
  1220. _fEscapePressed = TRUE;
  1221. }
  1222. // We got a mouse move message - we skip all the mouse messages
  1223. // till we get to the last one. The point here is that
  1224. // because of the length of DragOver calls, we can get behind
  1225. // in processing messages which causes odd things to happen
  1226. // on the screen.
  1227. if (WM_MOUSEMOVE == msg.message)
  1228. {
  1229. MSG msg2;
  1230. // Keep processing mouse move messages till there
  1231. // aren't any more.
  1232. // if PeekMessage returns true update the original msg.
  1233. while(PeekMessage(&msg2, 0, WM_MOUSEMOVE, WM_MOUSEMOVE,
  1234. PM_REMOVE))
  1235. {
  1236. msg = msg2;
  1237. }
  1238. }
  1239. // Record position of the mouse
  1240. _cpt.Set(msg.pt.x, msg.pt.y);
  1241. // set mouse button state here
  1242. _grfKeyState = GetControlKeysStateOfParam(msg.wParam);
  1243. }
  1244. else if (msg.message >= WM_NCMOUSEFIRST &&
  1245. msg.message <= WM_NCMOUSELAST)
  1246. {
  1247. // Nothing we need to do for these NC mouse actions
  1248. NULL;
  1249. }
  1250. else if ( (msg.message == WM_TIMER) && (msg.wParam == uTimer) )
  1251. {
  1252. // Our timer was triggered. We need to recheck the keyboard
  1253. // state just in case it has changed. This is important for
  1254. // the Chicago shell--if it doesn't have focus, then we won't
  1255. // get any WM_KEYDOWN message (just mouse moves).
  1256. _grfKeyState = GetControlKeysState(FALSE) | (_grfKeyState &
  1257. (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON));
  1258. if( GetKeyState(VK_ESCAPE) < 0 )
  1259. {
  1260. _fEscapePressed = TRUE;
  1261. }
  1262. // go ahead and fall out of the loop so we call DragOver
  1263. // (our timeout expired).
  1264. }
  1265. else
  1266. {
  1267. // Dispatch all other messages
  1268. DispatchMessage(&msg);
  1269. fMsg = FALSE;
  1270. }
  1271. }
  1272. else
  1273. {
  1274. WaitMessage();
  1275. }
  1276. // we have to leave the loop periodicially since apps
  1277. // might rely on on it the DragOver is called freqeuntly.
  1278. } while (!fMsg);
  1279. // Get rid of the timer we created for the loop
  1280. KillTimer(NULL, uTimer);
  1281. DDDebugOut((DEB_ITRACE, "%p OUT CDragOperation::HandleMessages ( %lx )\n",
  1282. this, fResult));
  1283. return fResult;
  1284. }
  1285. //+-------------------------------------------------------------------------
  1286. //
  1287. // Function: CDragOperation::CompleteDrop
  1288. //
  1289. // Synopsis: Complete the drag/drop operation
  1290. //
  1291. // Returns: Result of operation
  1292. //
  1293. // Algorithm: If there is a target and we have decided to drop, then
  1294. // drop. Otherwise, release the target and return whatever
  1295. // the other result of the operation was.
  1296. //
  1297. // History: dd-mmm-yy Author Comment
  1298. // 04-Apr-94 Ricksa Created
  1299. //
  1300. //--------------------------------------------------------------------------
  1301. HRESULT CDragOperation::CompleteDrop(void)
  1302. {
  1303. VDATEHEAP();
  1304. DDDebugOut((DEB_ITRACE, "%p _IN CDragOperation::CompleteDrop ( )\n",
  1305. this));
  1306. // Stop the mouse capture in case a dialog box is thrown up.
  1307. ReleaseCapture();
  1308. if (_pDropTarget != NULL)
  1309. {
  1310. // Caller is Drag/Drop aware
  1311. // and indicated it might accept drop
  1312. // The drop source replies DRAG_S_DROP if the user has
  1313. // released the left mouse button. However, we may be over
  1314. // a drop target which has refused a drop (via the feedback
  1315. // DROPEFFECT_NONE). Thus, both the drop source and drop
  1316. // target need to agree before we commit the drop.
  1317. if ((DRAGDROP_S_DROP == GetScode(_hrDragResult))
  1318. && (*_pdwEffect != DROPEFFECT_NONE))
  1319. {
  1320. // We are going to try to drop
  1321. *_pdwEffect = _dwOKEffects;
  1322. HRESULT hr = _pDropTarget->Drop(_pDataObject, _grfKeyState,
  1323. _cpt.GetPOINTL(), _pdwEffect);
  1324. if (FAILED(hr))
  1325. {
  1326. // If drop actually failed in the last stage, let the
  1327. // caller know that this happened.
  1328. _hrDragResult = hr;
  1329. }
  1330. }
  1331. else
  1332. {
  1333. *_pdwEffect = DROPEFFECT_NONE;
  1334. _pDropTarget->DragLeave();
  1335. }
  1336. _pDropTarget->Release();
  1337. _pDropTarget = NULL;
  1338. }
  1339. else
  1340. {
  1341. *_pdwEffect = DROPEFFECT_NONE;
  1342. }
  1343. DDDebugOut((DEB_ITRACE, "%p OUT CDragOperation::CompleteDrop ( %lx )\n",
  1344. this, _hrDragResult));
  1345. return _hrDragResult;
  1346. }
  1347. //+-------------------------------------------------------------------------
  1348. //
  1349. // Function: RegisterDragDrop
  1350. //
  1351. // Synopsis: Registers a drop target
  1352. //
  1353. // Arguments: [hwnd] -- a handle to the drop target window
  1354. // [pDropTarget] -- the IDropTarget interface for the window
  1355. //
  1356. // Returns: HRESULT
  1357. //
  1358. // Algorithm: We ask compobj (via AssignEndpoinProperty) to put an
  1359. // endpoint ID publicly available on the window handle. Then
  1360. // we put the IDropTarget pointer on the window as a private
  1361. // property (see the notes at the beginning of this file).
  1362. //
  1363. // History: dd-mmm-yy Author Comment
  1364. // 06-Apr-94 ricksa Added tracing
  1365. // 16-Jan-94 alexgo pDropTarget is now AddRef'ed
  1366. // 11-Jan-94 alexgo added VDATEHEAP, converted to RPC-style
  1367. // drag drop.
  1368. // 06-Dec-93 alexgo commented
  1369. //
  1370. // Notes: By AddRef'ing the pDropTarget pointer, we are changing
  1371. // the semantics of the 16bit code (which did not do an
  1372. // AddRef).
  1373. //
  1374. //--------------------------------------------------------------------------
  1375. #pragma SEG(RegisterDragDrop)
  1376. STDAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
  1377. {
  1378. HRESULT hresult = NOERROR;
  1379. BOOL fDelayDrop = FALSE;
  1380. VDATEHEAP();
  1381. OLETRACEIN((API_RegisterDragDrop, PARAMFMT("hwnd= %h, pDropTarget= %p"),
  1382. hwnd, pDropTarget));
  1383. DDDebugOut((DEB_ITRACE, "%p _IN RegisterDragDrop ( %lx %p )\n",
  1384. NULL, hwnd, pDropTarget));
  1385. if (!IsValidInterface(pDropTarget))
  1386. {
  1387. hresult = E_INVALIDARG;
  1388. }
  1389. else if (!IsWindow(hwnd))
  1390. {
  1391. hresult = DRAGDROP_E_INVALIDHWND;
  1392. }
  1393. else
  1394. {
  1395. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IDropTarget,(IUnknown **)&pDropTarget);
  1396. if (GetProp(hwnd, (LPCWSTR)g_aDropTarget))
  1397. {
  1398. hresult = DRAGDROP_E_ALREADYREGISTERED;
  1399. }
  1400. else if (!SetProp(hwnd, (LPCWSTR)g_aDropTarget, (HANDLE)pDropTarget))
  1401. {
  1402. hresult = E_OUTOFMEMORY;
  1403. }
  1404. else
  1405. {
  1406. DWORD dwAssignAptID;
  1407. Win4Assert(NOERROR == hresult);
  1408. // HACK: We need to add this atom every time RegisterDragDrop
  1409. // is called because 16-bit Word does not call RevokeDragDrop
  1410. // and user will automatically clean-up this atom if Word is the
  1411. // first app run, and then exited before another app calls
  1412. // RegisterDragDrop.
  1413. g_aEndPointAtom = GlobalAddAtom(ENDPOINT_PROP_NAME);
  1414. // See if Delayed Drop can be set up.
  1415. fDelayDrop = FALSE;
  1416. if (g_aDropTargetMarshalHwnd && IsApartmentInitialized())
  1417. {
  1418. HWND hwndClipboard = GetPrivateClipboardWindow(CLIP_CREATEIFNOTTHERE);
  1419. if (hwndClipboard)
  1420. {
  1421. fDelayDrop = SetProp(hwnd,(LPCWSTR) g_aDropTargetMarshalHwnd,hwndClipboard);
  1422. }
  1423. }
  1424. // if can't delay marshal then marshal immediately.
  1425. if (!fDelayDrop)
  1426. {
  1427. hresult = AssignEndpointProperty(hwnd);
  1428. }
  1429. if (NOERROR == hresult)
  1430. {
  1431. pDropTarget->AddRef();
  1432. }
  1433. else
  1434. {
  1435. // We don't free h. It's not a handle at all.
  1436. HANDLE h = RemoveProp(hwnd, (LPCWSTR)g_aDropTarget);
  1437. }
  1438. }
  1439. }
  1440. DDDebugOut((DEB_ITRACE, "%p OUT RegisterDragDrop ( %lx )\n",
  1441. NULL, hresult));
  1442. OLETRACEOUT((API_RegisterDragDrop, hresult));
  1443. return hresult;
  1444. }
  1445. //+-------------------------------------------------------------------------
  1446. //
  1447. // Function: RevokeDragDrop
  1448. //
  1449. // Synopsis: Unregisters a window as a drop target
  1450. //
  1451. // Arguments: [hwnd] -- the window to unregister
  1452. //
  1453. // Returns: HRESULT
  1454. //
  1455. // Algorithm: Removes the two window properties set by
  1456. // RegisterDragDrop
  1457. //
  1458. // History: dd-mmm-yy Author Comment
  1459. // 06-Apr-94 ricksa added tracing
  1460. // 16-Jan-94 alexgo added a Release to the drag drop
  1461. // pointer to match the AddRef in
  1462. // RegisterDragDrop.
  1463. // 11-Jan-94 alexgo converted to RPC-style drag drop,
  1464. // added VDATEHEAP macro
  1465. // 06-Dec-93 alexgo commented
  1466. //
  1467. // Notes: the DropTarget->Release call changes the semantics of
  1468. // this function from the 16bit version (see Notes: for
  1469. // RegisterDragDrop).
  1470. //
  1471. //--------------------------------------------------------------------------
  1472. #pragma SEG(RevokeDragDrop)
  1473. STDAPI RevokeDragDrop(HWND hwnd)
  1474. {
  1475. HRESULT hr = NOERROR;
  1476. LPDROPTARGET pDropTarget;
  1477. BOOL fReleaseDropTarget = TRUE;
  1478. VDATEHEAP();
  1479. OLETRACEIN((API_RevokeDragDrop, PARAMFMT("hwnd= %h"), hwnd));
  1480. DDDebugOut((DEB_ITRACE, "%p _IN RevokeDragDrop ( %lx )\n", NULL, hwnd));
  1481. if (!IsWindow(hwnd))
  1482. {
  1483. hr = DRAGDROP_E_INVALIDHWND;
  1484. }
  1485. else if ((pDropTarget = (LPDROPTARGET)RemoveProp(hwnd, (LPCWSTR)g_aDropTarget)) == NULL)
  1486. {
  1487. hr = DRAGDROP_E_NOTREGISTERED;
  1488. }
  1489. else
  1490. {
  1491. fReleaseDropTarget = TRUE;
  1492. if (GetProp(hwnd, (LPCWSTR) g_aEndPointAtom)) // see if there is an endpoint.
  1493. {
  1494. DWORD dwAssignAptID;
  1495. // Ask compobj to remove the endpoint ID it placed on the window.
  1496. if(SUCCEEDED(UnAssignEndpointProperty(hwnd,&dwAssignAptID)))
  1497. {
  1498. // Note: AptID == ThreadID in Apartment model.
  1499. if( (dwAssignAptID != GetCurrentThreadId()) && (IsApartmentInitialized()) )
  1500. {
  1501. fReleaseDropTarget = FALSE;
  1502. }
  1503. }
  1504. Win4Assert(NULL == GetProp(hwnd,(LPCWSTR) g_aDropTargetMarshalHwnd));
  1505. }
  1506. else
  1507. {
  1508. HWND hwndClipbrd;
  1509. hwndClipbrd = (HWND) RemoveProp(hwnd,(LPCWSTR) g_aDropTargetMarshalHwnd);
  1510. Win4Assert(hwndClipbrd);
  1511. fReleaseDropTarget = (IsApartmentInitialized() && (hwndClipbrd != GetPrivateClipboardWindow(CLIP_QUERY )) )
  1512. ? FALSE : TRUE;
  1513. }
  1514. // Release our reference to the object since we are no longer using it.
  1515. // NOTE: AddRef came from RegisterDragDrop
  1516. // Warning: Only call Release if we are in the same thread that Registered the DropTarget
  1517. // Or we are FreeThreading.
  1518. // This mirrors the atom added in RegisterDragDrop
  1519. GlobalDeleteAtom(g_aEndPointAtom);
  1520. if (fReleaseDropTarget)
  1521. {
  1522. pDropTarget->Release();
  1523. hr = NOERROR; // Always return NOERROR even if UnAssignEndPoint Failed
  1524. }
  1525. else
  1526. {
  1527. LEDebugOut((DEB_WARN, "WARNING:Revoke Called on Different Thread than Register!!\n"));
  1528. hr = RPC_E_WRONG_THREAD;
  1529. }
  1530. }
  1531. DDDebugOut((DEB_ITRACE, "%p OUT RegisterDragDrop ( %lx )\n", NULL, hr));
  1532. OLETRACEOUT((API_RevokeDragDrop, hr));
  1533. return hr;
  1534. }
  1535. //+-------------------------------------------------------------------------
  1536. //
  1537. // Function: DoDragDrop
  1538. //
  1539. // Synopsis: The main drag'n'drop loop
  1540. //
  1541. // Effects:
  1542. //
  1543. // Arguments: [pDataObject] -- the object to drag
  1544. // [pDropSource] -- the drop source
  1545. // [dwOKEffects] -- effects flags (stuff to draw)
  1546. // [pdwEffect] -- what actually happened in
  1547. // the drag drop attempt
  1548. //
  1549. // Requires:
  1550. //
  1551. // Returns:
  1552. //
  1553. // Signals:
  1554. //
  1555. // Modifies:
  1556. //
  1557. // Algorithm: See the notes at the beginning of the file
  1558. //
  1559. // History: dd-mmm-yy Author Comment
  1560. // 25-Nov-96 gopalk Fail the call if OleInitialize has not
  1561. // been called
  1562. // 05-Dec-94 JohannP added stack switching for WIN95
  1563. // 11-Jan-94 alexgo added VDATEHEAP macro, converted to
  1564. // the RPC-style drag drop.
  1565. // 31-Dec-93 erikgav chicago port
  1566. // 06-Dec-93 alexgo formatted
  1567. //
  1568. // Notes: Under Win95 SSAPI(DoDragDrop) gets expanded to SSDoDragDrop.
  1569. // This function is called by DoDragDrop (in stkswtch.cxx)
  1570. // which switches to the 16 bit stack first.
  1571. // IMPORTANT: this function has to be executed on the 16 bit
  1572. // since call back via USER might occur.
  1573. //--------------------------------------------------------------------------
  1574. #pragma SEG(DoDragDrop)
  1575. STDAPI SSAPI(DoDragDrop)(LPDATAOBJECT pDataObject, LPDROPSOURCE pDropSource,
  1576. DWORD dwOKEffects, DWORD *pdwEffect)
  1577. {
  1578. OLETRACEIN((API_DoDragDrop,
  1579. PARAMFMT("pDataObject=%p, pDropSource=%p, dwOKEffects=%x, pdwEffect=%p"),
  1580. pDataObject, pDropSource, dwOKEffects, pdwEffect));
  1581. DDDebugOut((DEB_ITRACE, "%p _IN DoDragDrop (%p %p %lx %p )\n",
  1582. NULL, pDataObject, pDropSource, dwOKEffects, pdwEffect));
  1583. HRESULT hr = NOERROR;
  1584. #ifndef _MAC
  1585. // Validation checks
  1586. VDATEHEAP();
  1587. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IDataObject,(IUnknown **)&pDataObject);
  1588. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IDropSource,(IUnknown **)&pDropSource);
  1589. if(!IsValidPtrOut(pdwEffect, sizeof(DWORD)) ||
  1590. !IsValidInterface(pDropSource) ||
  1591. !IsValidInterface(pDataObject))
  1592. hr = E_INVALIDARG;
  1593. // Check if the thread has called oleinitialize
  1594. if(!IsOleInitialized())
  1595. hr = CO_E_NOTINITIALIZED;
  1596. if(hr == NOERROR) {
  1597. // Create the object that does all the work.
  1598. CDragOperation drgop(pDataObject, pDropSource, dwOKEffects, pdwEffect, hr);
  1599. // Did the constructor succeeded?
  1600. if(SUCCEEDED(hr)) {
  1601. // Loop till worker object tells us to stop
  1602. for(;;) {
  1603. // Update target based on new window position
  1604. if(!drgop.UpdateTarget()) {
  1605. // Error so we are done
  1606. break;
  1607. }
  1608. // Notify
  1609. if(!drgop.DragOver()) {
  1610. break;
  1611. }
  1612. // Handle any messages we get in the mean time
  1613. if(!drgop.HandleMessages()) {
  1614. break;
  1615. }
  1616. } // end for loop
  1617. hr = drgop.CompleteDrop();
  1618. }
  1619. }
  1620. #endif // !_MAC
  1621. DDDebugOut((DEB_ITRACE, "%p OUT DoDragDrop ( %lx )\n", NULL, hr));
  1622. OLETRACEOUT((API_DoDragDrop, hr));
  1623. return hr;
  1624. }
  1625. //+-------------------------------------------------------------------------
  1626. //
  1627. // Member: CDropTarget::CDropTarget
  1628. //
  1629. // Synopsis: constructor for the CDropTarget class
  1630. //
  1631. // Effects:
  1632. //
  1633. // Arguments: [hwnd31] -- the hwnd of the Win3.1 drop target
  1634. // may be NULL
  1635. // [hwndOLE] -- the hwnd of the OLE drop target
  1636. // [dwEffectLast] -- the last effect given the the current
  1637. // drop target that we are to emulate
  1638. // [pdo] -- a pointer to the main drag drop class
  1639. // [hDDInfo] -- handle to cached drag drag info
  1640. //
  1641. //
  1642. // Requires: hwnd31 *must* be a handle to a valid Win3.1 drop source
  1643. //
  1644. // Returns: void
  1645. //
  1646. // Signals:
  1647. //
  1648. // Modifies:
  1649. //
  1650. // Derivation:
  1651. //
  1652. // Algorithm: initializes variables
  1653. //
  1654. // History: dd-mmm-yy Author Comment
  1655. // 20-Oct-94 alexgo author
  1656. // 08-Jan-95
  1657. //
  1658. // Notes: there are two ways of determining if a given hwnd is
  1659. // a valid Win3.1 drop target:
  1660. // 1. send a WM_QUERYDROPOBJECT message for a TRUE/FALSE
  1661. // reply
  1662. // 2. check the extended style bits for WS_EX_ACCEPTFILES
  1663. //
  1664. // if ptarget is non-NULL, then the specific window to which
  1665. // it belongs is *not* guaranteed to be the same window as
  1666. // hwndtarget. hwndtarget is the window that is registered as
  1667. // a Win3.1 target. All that is guaranteed is that the ole
  1668. // target and hwndtarget are in the same window hierarchy.
  1669. //
  1670. //--------------------------------------------------------------------------
  1671. CDropTarget::CDropTarget( HWND hwnd31, HWND hwndOLE, DWORD dwEffectLast,
  1672. CDragOperation *pdo, DDInfo hDDInfo )
  1673. {
  1674. _crefs = 1;
  1675. _hwndOLE = hwndOLE;
  1676. _hwnd31 = hwnd31;
  1677. _hDDInfo = hDDInfo;
  1678. _dwEffectLast = dwEffectLast;
  1679. _pdo = pdo; // pointer to the current drag operation class
  1680. #if DBG ==1
  1681. // now do some checking (see Notes above)
  1682. if( hwnd31 )
  1683. {
  1684. LONG exstyle;
  1685. exstyle = GetWindowLong(hwnd31, GWL_EXSTYLE);
  1686. // strictly speaking, an app could process the WM_QUERYDROPOBJECT
  1687. // message itself (and thus, not set the extended style bits).
  1688. // However, this should be considered an application bug; the
  1689. // documentation states that apps should call DragAcceptFiles,
  1690. // which will set the WS_EX_ACCEPTFILES bit
  1691. Assert( (exstyle & WS_EX_ACCEPTFILES) );
  1692. }
  1693. #endif // DBG ==1
  1694. }
  1695. //+-------------------------------------------------------------------------
  1696. //
  1697. // Member: CDropTarget::~CDropTarget
  1698. //
  1699. // Synopsis: frees the cached drag drop info handle
  1700. //
  1701. // Effects:
  1702. //
  1703. // Arguments: void
  1704. //
  1705. // Requires:
  1706. //
  1707. // Returns: void
  1708. //
  1709. // Signals:
  1710. //
  1711. // Modifies:
  1712. //
  1713. // Derivation:
  1714. //
  1715. // Algorithm:
  1716. //
  1717. // History: dd-mmm-yy Author Comment
  1718. // 08-Jan-95 alexgo author
  1719. //
  1720. // Notes:
  1721. //
  1722. //--------------------------------------------------------------------------
  1723. CDropTarget::~CDropTarget()
  1724. {
  1725. if( _hDDInfo )
  1726. {
  1727. FreeDragDropInfo(_hDDInfo);
  1728. }
  1729. }
  1730. //+-------------------------------------------------------------------------
  1731. //
  1732. // Member: CDropTarget::QueryInterface
  1733. //
  1734. // Synopsis: returns available interfaces on this object
  1735. //
  1736. // Effects:
  1737. //
  1738. // Arguments: [riid] -- the requested interface
  1739. // [ppv] -- where to put the interface
  1740. //
  1741. // Requires:
  1742. //
  1743. // Returns: E_UNEXPECTED
  1744. //
  1745. // Signals:
  1746. //
  1747. // Modifies:
  1748. //
  1749. // Derivation: IDropTarget
  1750. //
  1751. // Algorithm: CDropTarget is only used internally by OLE's drag drop code.
  1752. // It should never do a QI.
  1753. //
  1754. // History: dd-mmm-yy Author Comment
  1755. // 20-Oct-94 alexgo author
  1756. //
  1757. // Notes:
  1758. //
  1759. //--------------------------------------------------------------------------
  1760. STDMETHODIMP CDropTarget::QueryInterface( REFIID riid, LPVOID * ppv )
  1761. {
  1762. (void)riid; // unused;
  1763. (void)ppv; // unused;
  1764. AssertSz(0, "Unexpected QI to CDropTarget");
  1765. return E_UNEXPECTED;
  1766. }
  1767. //+-------------------------------------------------------------------------
  1768. //
  1769. // Member: CDropTarget::AddRef
  1770. //
  1771. // Synopsis: increments the reference count
  1772. //
  1773. // Effects:
  1774. //
  1775. // Arguments: void
  1776. //
  1777. // Requires:
  1778. //
  1779. // Returns: ULONG, the new reference count
  1780. //
  1781. // Signals:
  1782. //
  1783. // Modifies:
  1784. //
  1785. // Derivation: IDropTarget
  1786. //
  1787. // Algorithm:
  1788. //
  1789. // History: dd-mmm-yy Author Comment
  1790. // 20-Oct-94 alexgo author
  1791. //
  1792. // Notes:
  1793. //
  1794. //--------------------------------------------------------------------------
  1795. STDMETHODIMP_(ULONG) CDropTarget::AddRef( void )
  1796. {
  1797. VDATEHEAP();
  1798. DDDebugOut((DEB_ITRACE, "%p _IN CDropTarget::AddRef ( )\n", this));
  1799. _crefs++;
  1800. DDDebugOut((DEB_ITRACE, "%p OUT CDropTarget::AddRef ( %ld )\n", this,
  1801. _crefs));
  1802. return _crefs;
  1803. }
  1804. //+-------------------------------------------------------------------------
  1805. //
  1806. // Member: CDropTarget::Release
  1807. //
  1808. // Synopsis: decrements the reference count
  1809. //
  1810. // Effects: may delete 'this' object
  1811. //
  1812. // Arguments: void
  1813. //
  1814. // Requires:
  1815. //
  1816. // Returns: ULONG, the new reference count
  1817. //
  1818. // Signals:
  1819. //
  1820. // Modifies:
  1821. //
  1822. // Derivation: IDropTarget
  1823. //
  1824. // Algorithm:
  1825. //
  1826. // History: dd-mmm-yy Author Comment
  1827. // 20-Oct-94 alexgo author
  1828. //
  1829. // Notes:
  1830. //
  1831. //--------------------------------------------------------------------------
  1832. STDMETHODIMP_(ULONG) CDropTarget::Release( void )
  1833. {
  1834. ULONG crefs;
  1835. VDATEHEAP();
  1836. DDDebugOut((DEB_ITRACE, "%p _IN CDropTarget::Release ( )\n", this));
  1837. crefs = --_crefs;
  1838. if( crefs == 0)
  1839. {
  1840. DDDebugOut((DEB_ITRACE, "DELETING CDropTarget %p\n", this));
  1841. delete this;
  1842. }
  1843. DDDebugOut((DEB_ITRACE, "%p OUT CDropTarget::Release ( %ld )\n",
  1844. this, crefs));
  1845. return crefs;
  1846. }
  1847. //+-------------------------------------------------------------------------
  1848. //
  1849. // Member: CDropTarget::DragEnter
  1850. //
  1851. // Synopsis: sets the window up for drag drop
  1852. //
  1853. // Effects:
  1854. //
  1855. // Arguments: [pDataObject] -- the data object to drop
  1856. // [grfKeyState] -- the current keyboard state
  1857. // [pt] -- the cursor point
  1858. // [pdwEffect] -- where to return the drag drop effect
  1859. //
  1860. // Requires:
  1861. //
  1862. // Returns: HRESULT
  1863. //
  1864. // Signals:
  1865. //
  1866. // Modifies:
  1867. //
  1868. // Derivation: IDropTarget
  1869. //
  1870. // Algorithm: should never be called. DragEnter is always called
  1871. // via GetDropTarget
  1872. //
  1873. // History: dd-mmm-yy Author Comment
  1874. // 08-Nov-93 alexgo eliminated
  1875. // 20-Oct-94 alexgo author
  1876. //
  1877. // Notes:
  1878. //
  1879. //--------------------------------------------------------------------------
  1880. STDMETHODIMP CDropTarget::DragEnter( IDataObject * pDataObject,
  1881. DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect )
  1882. {
  1883. AssertSz(0, "DragEnter unexpectedly called!");
  1884. return E_UNEXPECTED;
  1885. }
  1886. //+-------------------------------------------------------------------------
  1887. //
  1888. // Member: CDropTarget::DragOver
  1889. //
  1890. // Synopsis: called while the mouse is over a given window
  1891. //
  1892. // Effects:
  1893. //
  1894. // Arguments: [grfKeyState] -- the state of the keyboard
  1895. // [ptl] -- the position of the cursor
  1896. // [pdwEffect] -- the drag drop effect
  1897. //
  1898. // Requires:
  1899. //
  1900. // Returns: NOERROR
  1901. //
  1902. // Signals:
  1903. //
  1904. // Modifies:
  1905. //
  1906. // Derivation: IDropTarget
  1907. //
  1908. // Algorithm: If an OLE target is available, then we forward the call.
  1909. // If the target says DROPEFFECT_NONE, then we go ahead
  1910. // and return DROPEFFECT_COPY if a Win31 target window is
  1911. // available.
  1912. //
  1913. // If there is no OLE target and we have a Win3.1 target,
  1914. // then we go ahead and return DROPEFFECT_COPY.
  1915. //
  1916. // History: dd-mmm-yy Author Comment
  1917. // 08-Nov-94 alexgo converted to PrivDragDrop protocol
  1918. // 20-Oct-94 alexgo author
  1919. //
  1920. // Notes:
  1921. //
  1922. //--------------------------------------------------------------------------
  1923. STDMETHODIMP CDropTarget::DragOver( DWORD grfKeyState, POINTL ptl,
  1924. DWORD *pdwEffect)
  1925. {
  1926. HRESULT hresult = NOERROR;
  1927. VDATEHEAP();
  1928. DDDebugOut((DEB_ITRACE, "%p _IN CDropTarget::DragOver ( %lx , %lx "
  1929. ", %lx )\n", this, grfKeyState, &ptl, *pdwEffect));
  1930. if( _hwndOLE )
  1931. {
  1932. hresult = PrivDragDrop(_hwndOLE, DRAGOP_OVER, NULL, NULL, grfKeyState,
  1933. ptl, pdwEffect, NULL, &_hDDInfo);
  1934. _dwEffectLast = *pdwEffect;
  1935. if( _hwnd31 )
  1936. {
  1937. // we only want to stomp on the effect if the DragOver call
  1938. // succeeded. If the call failed, then just assume that a
  1939. // Win3.1 drop would fail as well.
  1940. if( hresult == NOERROR && *pdwEffect == DROPEFFECT_NONE )
  1941. {
  1942. *pdwEffect = DROPEFFECT_COPY;
  1943. }
  1944. }
  1945. }
  1946. else if ( _hwnd31 )
  1947. {
  1948. *pdwEffect = DROPEFFECT_COPY;
  1949. }
  1950. DDDebugOut((DEB_ITRACE, "%p OUT CDropTarget::DragOver ( %lx ) [ "
  1951. "%lx ]\n", this, hresult, *pdwEffect));
  1952. return hresult;
  1953. }
  1954. //+-------------------------------------------------------------------------
  1955. //
  1956. // Member: CDropTarget::DragLeave
  1957. //
  1958. // Synopsis: called when the cursor leaves the current target window
  1959. //
  1960. // Effects:
  1961. //
  1962. // Arguments: void
  1963. //
  1964. // Requires:
  1965. //
  1966. // Returns: NOERROR
  1967. //
  1968. // Signals:
  1969. //
  1970. // Modifies:
  1971. //
  1972. // Derivation: IDropTarget
  1973. //
  1974. // Algorithm: Forwards the DragLeave call to the OLE-drop target
  1975. // (if it exists).
  1976. //
  1977. // History: dd-mmm-yy Author Comment
  1978. // 08-Nov-94 alexgo converted to PrivDragDrop protocol
  1979. // 20-Oct-94 alexgo author
  1980. //
  1981. // Notes:
  1982. //
  1983. //--------------------------------------------------------------------------
  1984. STDMETHODIMP CDropTarget::DragLeave()
  1985. {
  1986. HRESULT hresult = NOERROR;
  1987. static POINTL ptl = {0, 0};
  1988. VDATEHEAP();
  1989. DDDebugOut((DEB_ITRACE, "%p _IN CDropTarget::DragLeave ( )\n",
  1990. this));
  1991. if( _hwndOLE )
  1992. {
  1993. hresult = PrivDragDrop(_hwndOLE, DRAGOP_LEAVE, NULL, NULL, NULL,
  1994. ptl, NULL, NULL, &_hDDInfo);
  1995. }
  1996. DDDebugOut((DEB_ITRACE, "%p OUT CDropTarget::DragLeave ( %lx )\n",
  1997. this, hresult));
  1998. return hresult;
  1999. }
  2000. //+-------------------------------------------------------------------------
  2001. //
  2002. // Member: CDropTarget::Drop
  2003. //
  2004. // Synopsis: called if the user lets go of the mouse button while
  2005. // over a drop target
  2006. //
  2007. // Effects:
  2008. //
  2009. // Arguments: [pDataObject] -- the data object to use
  2010. // [grfKeyState] -- the keyboard state
  2011. // [ptl] -- the current mouse position
  2012. // [pdwEffect] -- where to return cursor effect feedback
  2013. //
  2014. // Requires:
  2015. //
  2016. // Returns: HRESULT
  2017. //
  2018. // Signals:
  2019. //
  2020. // Modifies:
  2021. //
  2022. // Derivation: IDropTarget
  2023. //
  2024. // Algorithm: If there is an OLE-target available, then we first forward
  2025. // the drop request to it. If the call fails
  2026. // (or DROPEFFECT_NONE is returned), then we try the Win31
  2027. // drop by posting a WM_DROPFILES message to the Win31 target
  2028. // window (ifit exists).
  2029. //
  2030. // History: dd-mmm-yy Author Comment
  2031. // 08-Nov-94 alexgo converted to PrivDragDrop protocol
  2032. // 20-Oct-94 alexgo author
  2033. //
  2034. // Notes:
  2035. //
  2036. //--------------------------------------------------------------------------
  2037. STDMETHODIMP CDropTarget::Drop( IDataObject *pDataObject,
  2038. DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect )
  2039. {
  2040. STGMEDIUM medium;
  2041. FORMATETC formatetc;
  2042. HRESULT hresult = E_FAIL;
  2043. IFBuffer DOBuffer = _pdo->GetDOBuffer();
  2044. VDATEHEAP();
  2045. DDDebugOut((DEB_ITRACE, "%p _IN CDropTarget::Drop ( %p , %lx , ",
  2046. "%p , %lx )\n", this, pDataObject, grfKeyState, &ptl, *pdwEffect));
  2047. // we don't forward Drop calls to the target if the last effect
  2048. // is DROPEFFECT_NONE. It is important that we check for this because
  2049. // to DoDragDrop 'normally' would not call Drop if the last effect
  2050. // was DROPEFFECT_NONE. However, this target wrapper will stomp
  2051. // pdwEffect and return DROPEFFECT_COPY instead of DROPEFFECT_NONE.
  2052. if( _hwndOLE && _dwEffectLast != DROPEFFECT_NONE )
  2053. {
  2054. hresult = PrivDragDrop(_hwndOLE, DRAGOP_DROP, DOBuffer, pDataObject,
  2055. grfKeyState, ptl, pdwEffect,
  2056. GetPrivateClipboardWindow(CLIP_QUERY), &_hDDInfo);
  2057. }
  2058. else if( _hwndOLE )
  2059. {
  2060. // if the 'real' drop effect is NONE, then we need to call
  2061. // DragLeave here before going on to post the WM_DROPFILES
  2062. // message. Otherwise, the app that is both an OLE and Win31
  2063. // and has been returning DROPEFFECT_NONE will never get a
  2064. // Drop or DragLeave call (which is necessary to terminate
  2065. // the OLE2 drag protocol). Capone in particular is sensitive
  2066. // to this.
  2067. *pdwEffect = DROPEFFECT_NONE;
  2068. hresult = DragLeave();
  2069. }
  2070. if( (hresult != NOERROR || *pdwEffect == DROPEFFECT_NONE) &&
  2071. (hresult != S_FALSE) &&
  2072. (_hwnd31) )
  2073. {
  2074. medium.tymed = TYMED_NULL;
  2075. INIT_FORETC(formatetc);
  2076. formatetc.cfFormat = CF_HDROP;
  2077. formatetc.tymed = TYMED_HGLOBAL;
  2078. hresult = pDataObject->GetData(&formatetc, &medium);
  2079. if( hresult == NOERROR )
  2080. {
  2081. // we need to fixup the mouse point coordinates in the CF_HDROP
  2082. // data. The point point should be in client coordinates
  2083. // (whereas IDropTarget::Drop takes screen coordinates)
  2084. DROPFILES *pdf = (DROPFILES *)GlobalLock(medium.hGlobal);
  2085. POINT pt;
  2086. pt.x = ptl.x;
  2087. pt.y = ptl.y;
  2088. if( pdf )
  2089. {
  2090. // we also need to set the non-client (NC) flag of the
  2091. // dropfile data. This lets the app do different behaviour
  2092. // depending on whether the drop point is in the client or
  2093. // non-client area (Word6, for example, opens the file if on
  2094. // non-client area, otherwise makes a package object).
  2095. pdf->fNC = IsNCDrop(_hwnd31, pt);
  2096. if( ScreenToClient(_hwnd31, &pt) )
  2097. {
  2098. pdf->pt.x = pt.x;
  2099. pdf->pt.y = pt.y;
  2100. }
  2101. else
  2102. {
  2103. LEDebugOut((DEB_WARN, "WARNING: CF_HDROP pt coords"
  2104. "not updated!!\n"));
  2105. ; // don't do anything
  2106. }
  2107. GlobalUnlock(medium.hGlobal);
  2108. }
  2109. else
  2110. {
  2111. LEDebugOut((DEB_WARN, "WARNING: OUT OF MEMORY!\n"));
  2112. ; // don't do anything
  2113. }
  2114. if( PostMessage(_hwnd31, WM_DROPFILES,
  2115. (WPARAM)medium.hGlobal, 0) )
  2116. {
  2117. *pdwEffect = DROPEFFECT_COPY;
  2118. }
  2119. else
  2120. {
  2121. // PostMessage failed, so free the data
  2122. ReleaseStgMedium(&medium);
  2123. *pdwEffect = DROPEFFECT_NONE;
  2124. }
  2125. }
  2126. }
  2127. DDDebugOut((DEB_ITRACE, "%p OUT CDropTarget::Drop ( %lx ) [ %lx ]\n",
  2128. this, hresult, *pdwEffect));
  2129. return hresult;
  2130. }