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.

2329 lines
70 KiB

  1. #include "shellprv.h"
  2. #include "defview.h"
  3. #include "lvutil.h"
  4. #include "ids.h"
  5. #include "idlcomm.h"
  6. #pragma hdrstop
  7. #include "datautil.h"
  8. #include "apithk.h"
  9. BOOL DAD_IsDraggingImage(void);
  10. void DAD_SetDragCursor(int idCursor);
  11. BOOL DAD_IsDragging();
  12. #define MONITORS_MAX 16 // Is this really the max?
  13. #define DCID_NULL 0
  14. #define DCID_NO 1
  15. #define DCID_MOVE 2
  16. #define DCID_COPY 3
  17. #define DCID_LINK 4
  18. #define DCID_MAX 5
  19. #define TF_DRAGIMAGES 0x02000000
  20. #define DRAGDROP_ALPHA 120
  21. #define MAX_WIDTH_ALPHA 200
  22. #define MAX_HEIGHT_ALPHA 200
  23. #define CIRCULAR_ALPHA // Circular Alpha Blending Centered on Center of image
  24. class CDragImages : public IDragSourceHelper, IDropTargetHelper
  25. {
  26. public:
  27. // IUnknown methods
  28. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  29. STDMETHODIMP_(ULONG) AddRef() { return 2; }; // One global Com object per process
  30. STDMETHODIMP_(ULONG) Release() { return 1; }; // One global Com object per process
  31. // IDragSourceHelper methods
  32. STDMETHODIMP InitializeFromBitmap(LPSHDRAGIMAGE pshdi, IDataObject* pdtobj);
  33. STDMETHODIMP InitializeFromWindow(HWND hwnd, POINT* ppt, IDataObject* pdtobj);
  34. // IDropTargetHelper methods
  35. STDMETHODIMP DragEnter(HWND hwndTarget, IDataObject* pdtobj, POINT* ppt, DWORD dwEffect);
  36. STDMETHODIMP DragLeave();
  37. STDMETHODIMP DragOver(POINT* ppt, DWORD dwEffect);
  38. STDMETHODIMP Drop(IDataObject* pdtobj, POINT* ppt, DWORD dwEffect);
  39. STDMETHODIMP Show(BOOL fShow);
  40. // These are public so the DAD_* routines can access.
  41. BOOL IsDragging() { return (Initialized() && _Single.bDragging); };
  42. BOOL IsDraggingImage() { return (Initialized() && _fImage && _Single.bDragging); };
  43. BOOL IsDraggingLayeredWindow() { return _shdi.hbmpDragImage != NULL; };
  44. BOOL SetDragImage(HIMAGELIST himl, int index, POINT * pptOffset);
  45. void SetDragCursor(int idCursor);
  46. HWND GetTarget() { return _hwndTarget; }
  47. BOOL Initialized();
  48. DWORD GetThread() { return _idThread; };
  49. void FreeDragData();
  50. void ThreadDetach();
  51. void ProcessDetach();
  52. // for drag source feedback communication
  53. void SetDropEffectCursor(int idCur);
  54. CDragImages() {};
  55. private:
  56. ~CDragImages();
  57. void _InitDragData();
  58. BOOL _IsLayeredSupported();
  59. HRESULT _SaveToDataObject(IDataObject* pdtobj);
  60. HRESULT _LoadFromDataObject(IDataObject* pdtobj);
  61. HRESULT _LoadLayeredBitmapBits(HGLOBAL hGlobal);
  62. HRESULT _SaveLayeredBitmapBits(HGLOBAL* phGlobal);
  63. BOOL _ShowDragImageInterThread(HWND hwndLock, BOOL * pfShow);
  64. // MultiRectDragging
  65. void _MultipleDragShow(BOOL bShow);
  66. void _MultipleDragStart(HWND hwndLock, LPRECT aRect, int nRects, POINT ptStart, POINT ptOffset);
  67. void _MultipleDragMove(POINT ptNew);
  68. HRESULT _SetLayeredDragging(LPSHDRAGIMAGE pshdi);
  69. HRESULT _SetMultiItemDragging(HWND hwndLV, int cItems, POINT *pptOffset);
  70. HRESULT _SetMultiRectDragging(int cItems, LPRECT prect, POINT *pptOffset);
  71. // Merged Cursors
  72. HBITMAP CreateColorBitmap(int cx, int cy);
  73. void _DestroyCachedCursors();
  74. HRESULT _GetCursorLowerRight(HCURSOR hcursor, int * px, int * py, POINT *pptHotSpot);
  75. int _MapCursorIDToImageListIndex(int idCur);
  76. int _AddCursorToImageList(HCURSOR hcur, LPCTSTR idMerge, POINT *pptHotSpot);
  77. BOOL _MergeIcons(HCURSOR hcursor, LPCTSTR idMerge, HBITMAP *phbmImage, HBITMAP *phbmMask, POINT* pptHotSpot);
  78. HCURSOR _SetCursorHotspot(HCURSOR hcur, POINT *ptHot);
  79. // Helper Routines
  80. BOOL _CreateDragWindow();
  81. BOOL _PreProcessDragBitmap(void** ppvBits);
  82. // Member Variables
  83. SHDRAGIMAGE _shdi;
  84. HWND _hwndTarget;
  85. HWND _hwnd; // The HWND of the Layered Window
  86. HDC _hdcDragImage;
  87. HBITMAP _hbmpOld;
  88. BOOL _fLayeredSupported;
  89. BOOL _fCursorDataInited;
  90. POINT _ptDebounce;
  91. // Legacy drag support
  92. BOOL _fImage;
  93. POINT _ptOffset;
  94. DWORD _idThread;
  95. HIMAGELIST _himlCursors;
  96. UINT _cRev;
  97. int _aindex[DCID_MAX]; // will be initialized.
  98. HCURSOR _ahcur[DCID_MAX];
  99. POINT _aptHotSpot[DCID_MAX];
  100. int _idCursor;
  101. // _Single struct is used between DAD_Enter and DAD_Leave
  102. struct
  103. {
  104. // Common part
  105. BOOL bDragging;
  106. BOOL bLocked;
  107. HWND hwndLock;
  108. BOOL bSingle; // Single imagelist dragging.
  109. DWORD idThreadEntered;
  110. // Multi-rect dragging specific part
  111. struct
  112. {
  113. BOOL bShown;
  114. LPRECT pRect;
  115. int nRects;
  116. POINT ptOffset;
  117. POINT ptNow;
  118. } _Multi;
  119. } _Single;
  120. // following fields are used only when fImage==FALSE
  121. RECT* _parc; // cItems
  122. UINT _cItems; // This is a sentinal. Needs to be the last item.
  123. };
  124. CDragImages::~CDragImages()
  125. {
  126. FreeDragData();
  127. }
  128. //
  129. // Read 'Notes' in CDropSource_GiveFeedback for detail about this
  130. // g_fDraggingOverSource flag, which is TRUE only if we are dragging
  131. // over the source window itself with left mouse button
  132. // (background and large/small icon mode only).
  133. //
  134. UINT g_cRev = 0;
  135. CDragImages* g_pdiDragImages = NULL;
  136. BOOL g_fDraggingOverSource = FALSE;
  137. STDAPI CDragImages_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppvOut)
  138. {
  139. ASSERT(pUnkOuter == NULL); //Who's trying to aggregate us?
  140. if (!g_pdiDragImages)
  141. g_pdiDragImages = new CDragImages();
  142. if (g_pdiDragImages && ppvOut) // ppvOut test for internal create usage
  143. return g_pdiDragImages->QueryInterface(riid, ppvOut);
  144. return E_OUTOFMEMORY;
  145. }
  146. STDMETHODIMP CDragImages::QueryInterface(REFIID riid, void **ppv)
  147. {
  148. static const QITAB qit[] = {
  149. QITABENT(CDragImages, IDragSourceHelper),
  150. QITABENT(CDragImages, IDropTargetHelper),
  151. { 0 },
  152. };
  153. return QISearch(this, qit, riid, ppv);
  154. }
  155. #define UM_KILLYOURSELF WM_USER
  156. LRESULT CALLBACK DragWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  157. {
  158. if (uMsg == UM_KILLYOURSELF)
  159. {
  160. DestroyWindow(hwnd);
  161. return 0;
  162. }
  163. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  164. }
  165. BOOL CDragImages::_CreateDragWindow()
  166. {
  167. if (_hwnd == NULL)
  168. {
  169. WNDCLASS wc = {0};
  170. wc.hInstance = g_hinst;
  171. wc.lpfnWndProc = DragWndProc;
  172. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  173. wc.lpszClassName = TEXT("SysDragImage");
  174. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); // NULL;
  175. SHRegisterClass(&wc);
  176. _hwnd = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW,
  177. TEXT("SysDragImage"), TEXT("Drag"), WS_POPUPWINDOW,
  178. 0, 0, 50, 50, NULL, NULL, g_hinst, NULL);
  179. if (!_hwnd)
  180. return FALSE;
  181. //
  182. // This window should not be mirrored so that the image contents won't be flipped. [samera]
  183. //
  184. SetWindowBits(_hwnd, GWL_EXSTYLE, RTL_MIRRORED_WINDOW, 0);
  185. }
  186. return TRUE;
  187. }
  188. BOOL CDragImages::Initialized()
  189. {
  190. return _fCursorDataInited;
  191. }
  192. void CDragImages::FreeDragData()
  193. {
  194. if (_hwnd)
  195. {
  196. SendMessage(_hwnd, UM_KILLYOURSELF, 0, 0);
  197. _hwnd = NULL;
  198. }
  199. _fCursorDataInited = FALSE;
  200. // Make sure we destroy the cursors on an invalidate.
  201. if (_himlCursors)
  202. _DestroyCachedCursors();
  203. // Do we have an array?
  204. if (_parc)
  205. {
  206. delete [] _parc;
  207. _parc = NULL;
  208. }
  209. if (_fImage)
  210. ImageList_EndDrag();
  211. if (_hbmpOld)
  212. {
  213. SelectObject(_hdcDragImage, _hbmpOld);
  214. _hbmpOld = NULL;
  215. }
  216. if (_hdcDragImage)
  217. {
  218. DeleteDC(_hdcDragImage);
  219. _hdcDragImage = NULL;
  220. }
  221. if (_shdi.hbmpDragImage)
  222. DeleteObject(_shdi.hbmpDragImage);
  223. ZeroMemory(&_Single, sizeof(_Single));
  224. ZeroMemory(&_shdi, sizeof(_shdi));
  225. _ptOffset.x = 0;
  226. _ptOffset.y = 0;
  227. _ptDebounce.x = 0;
  228. _ptDebounce.y = 0;
  229. _hwndTarget = _hwnd = NULL;
  230. _fCursorDataInited = _fLayeredSupported = FALSE;
  231. _fImage = FALSE;
  232. _idThread = 0;
  233. _himlCursors = NULL;
  234. _cRev = 0;
  235. _idCursor = 0;
  236. }
  237. void CDragImages::_InitDragData()
  238. {
  239. _idThread = GetCurrentThreadId();
  240. if (_himlCursors && _cRev != g_cRev)
  241. _DestroyCachedCursors();
  242. if (_himlCursors == NULL)
  243. {
  244. UINT uFlags = ILC_MASK | ILC_SHARED;
  245. if (IS_BIDI_LOCALIZED_SYSTEM())
  246. uFlags |= ILC_MIRROR;
  247. //
  248. // if this is not a palette device, use a DDB for the imagelist
  249. // this is important when displaying high-color cursors
  250. //
  251. HDC hdc = GetDC(NULL);
  252. if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE))
  253. {
  254. uFlags |= ILC_COLORDDB;
  255. }
  256. ReleaseDC(NULL, hdc);
  257. _himlCursors = ImageList_Create(GetSystemMetrics(SM_CXCURSOR),
  258. GetSystemMetrics(SM_CYCURSOR),
  259. uFlags, 1, 0);
  260. _cRev = g_cRev;
  261. // We need to initialize s_cursors._aindex[*]
  262. _MapCursorIDToImageListIndex(-1);
  263. }
  264. _fCursorDataInited = TRUE;
  265. }
  266. BOOL AreAllMonitorsAtLeast(int iBpp)
  267. {
  268. DISPLAY_DEVICE DisplayDevice;
  269. BOOL fAreAllMonitorsAtLeast = TRUE;
  270. for (int iEnum = 0; fAreAllMonitorsAtLeast && iEnum < MONITORS_MAX; iEnum++)
  271. {
  272. ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
  273. DisplayDevice.cb = sizeof(DisplayDevice);
  274. if (EnumDisplayDevices(NULL, iEnum, &DisplayDevice, 0) &&
  275. (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
  276. {
  277. HDC hdc = CreateDC(NULL, (LPTSTR)DisplayDevice.DeviceName, NULL, NULL);
  278. if (hdc)
  279. {
  280. int iBits = GetDeviceCaps(hdc, BITSPIXEL);
  281. if (iBits < iBpp)
  282. fAreAllMonitorsAtLeast = FALSE;
  283. DeleteDC(hdc);
  284. }
  285. }
  286. }
  287. return fAreAllMonitorsAtLeast;
  288. }
  289. BOOL CDragImages::_IsLayeredSupported()
  290. {
  291. // For the first rev, we will only support Layered drag images
  292. // when the Color depth is greater than 65k colors.
  293. // We should ask everytime....
  294. _fLayeredSupported = AreAllMonitorsAtLeast(16);
  295. if (_fLayeredSupported)
  296. {
  297. BOOL bDrag;
  298. if (SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &bDrag, 0))
  299. {
  300. _fLayeredSupported = BOOLIFY(bDrag);
  301. }
  302. if (_fLayeredSupported)
  303. _fLayeredSupported = SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("NewDragImages"), FALSE, TRUE);
  304. }
  305. return _fLayeredSupported;
  306. }
  307. //
  308. // initialize the static drag image manager from a structure
  309. // this is implemented for WindowLess controls that can act as a
  310. // drag source.
  311. //
  312. HRESULT CDragImages::_SetLayeredDragging(LPSHDRAGIMAGE pshdi)
  313. {
  314. // We don't support being initialized from a bitmap when Layered Windows are not supported
  315. HRESULT hr;
  316. if (_IsLayeredSupported())
  317. {
  318. RIP(IsValidHANDLE(pshdi->hbmpDragImage));
  319. _shdi = *pshdi; // Keep a copy of this.
  320. _idCursor = -1; // Initialize this... This is an arbitraty place and can be put
  321. // anywhere before the first Setcursor call
  322. _InitDragData();
  323. hr = S_OK;
  324. }
  325. else
  326. hr = E_FAIL;
  327. return hr;
  328. }
  329. STDMETHODIMP CDragImages::InitializeFromBitmap(LPSHDRAGIMAGE pshdi, IDataObject* pdtobj)
  330. {
  331. FreeDragData();
  332. HRESULT hr = _SetLayeredDragging(pshdi);
  333. if (SUCCEEDED(hr))
  334. {
  335. hr = _SaveToDataObject(pdtobj);
  336. if (FAILED(hr))
  337. FreeDragData();
  338. }
  339. return hr;
  340. }
  341. BOOL ListView_HasMask(HWND hwnd)
  342. {
  343. HIMAGELIST himl = ListView_GetImageList(hwnd, LVSIL_NORMAL);
  344. return himl && (ImageList_GetFlags(himl) & ILC_MASK);
  345. }
  346. //
  347. // initialize the static drag image manager from an HWND that
  348. // can process the RegisteredWindowMessage(DI_GETDRAGIMAGE)
  349. //
  350. STDMETHODIMP CDragImages::InitializeFromWindow(HWND hwnd, POINT* ppt, IDataObject* pdtobj)
  351. {
  352. HRESULT hr = E_FAIL;
  353. FreeDragData();
  354. if (_IsLayeredSupported())
  355. {
  356. // Register the message that gets us the Bitmap from the control.
  357. static int g_msgGetDragImage = 0;
  358. if (g_msgGetDragImage == 0)
  359. g_msgGetDragImage = RegisterWindowMessage(DI_GETDRAGIMAGE);
  360. // Can this HWND generate a drag image for me?
  361. if (g_msgGetDragImage && SendMessage(hwnd, g_msgGetDragImage, 0, (LPARAM)&_shdi))
  362. {
  363. // Yes; Now we select that into the window
  364. hr = _SetLayeredDragging(&_shdi);
  365. }
  366. }
  367. if (FAILED(hr))
  368. {
  369. TCHAR szClassName[50];
  370. if (GetClassName(hwnd, szClassName, ARRAYSIZE(szClassName)))
  371. {
  372. if (lstrcmpi(szClassName, WC_LISTVIEW) == 0)
  373. {
  374. POINT ptOffset = {0,0};
  375. if (ppt)
  376. ptOffset = *ppt;
  377. int cItems = ListView_GetSelectedCount(hwnd);
  378. if (cItems >= 1)
  379. {
  380. if ((cItems == 1) && ListView_HasMask(hwnd))
  381. {
  382. POINT ptTemp;
  383. HIMAGELIST himl = ListView_CreateDragImage(hwnd, ListView_GetNextItem(hwnd, -1, LVNI_SELECTED), &ptTemp);
  384. if (himl)
  385. {
  386. ClientToScreen(hwnd, &ptTemp);
  387. ptOffset.x -= ptTemp.x;
  388. // Since the listview is mirrored, then mirror the selected
  389. // icon coord. This would result in negative offset so let's
  390. // compensate. [samera]
  391. if (IS_WINDOW_RTL_MIRRORED(hwnd))
  392. ptOffset.x *= -1;
  393. ptOffset.y -= ptTemp.y;
  394. SetDragImage(himl, 0, &ptOffset);
  395. ImageList_Destroy(himl);
  396. hr = S_OK;
  397. }
  398. }
  399. else
  400. {
  401. hr = _SetMultiItemDragging(hwnd, cItems, &ptOffset);
  402. }
  403. }
  404. }
  405. else if (lstrcmpi(szClassName, WC_TREEVIEW) == 0)
  406. {
  407. HIMAGELIST himlDrag = TreeView_CreateDragImage(hwnd, NULL);
  408. if (himlDrag)
  409. {
  410. SetDragImage(himlDrag, 0, NULL);
  411. ImageList_Destroy(himlDrag);
  412. hr = S_OK;
  413. }
  414. }
  415. }
  416. }
  417. if (SUCCEEDED(hr))
  418. {
  419. // ignore failure here as this will still work in process due to the globals
  420. // fonts folder depends on this
  421. _SaveToDataObject(pdtobj);
  422. }
  423. return hr;
  424. }
  425. //
  426. // create the drag window in the layered window case, or to begin drawing the
  427. // Multi Rect or icon drag images.
  428. //
  429. STDMETHODIMP CDragImages::DragEnter(HWND hwndTarget, IDataObject* pdtobj, POINT* ppt, DWORD dwEffect)
  430. {
  431. HRESULT hr = _LoadFromDataObject(pdtobj);
  432. if (SUCCEEDED(hr))
  433. {
  434. _hwndTarget = hwndTarget ? hwndTarget : GetDesktopWindow();
  435. SetDragCursor(-1);
  436. _Single.bDragging = TRUE;
  437. _Single.bSingle = _fImage;
  438. _Single.hwndLock = _hwndTarget;
  439. _Single.bLocked = FALSE;
  440. _Single.idThreadEntered = GetCurrentThreadId();
  441. _ptDebounce.x = 0;
  442. _ptDebounce.y = 0;
  443. if (_shdi.hbmpDragImage)
  444. {
  445. TraceMsg(TF_DRAGIMAGES, "CDragImages::DragEnter : Creating Drag Window");
  446. // At this point the information has been read from the data object.
  447. // Reconstruct the HWND if necessary
  448. if (_CreateDragWindow() && _hdcDragImage)
  449. {
  450. POINT ptSrc = {0, 0};
  451. POINT pt;
  452. SetWindowPos(_hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE |
  453. SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  454. GetMsgPos(&pt);
  455. pt.x -= _shdi.ptOffset.x;
  456. pt.y -= _shdi.ptOffset.y;
  457. BLENDFUNCTION blend;
  458. blend.BlendOp = AC_SRC_OVER;
  459. blend.BlendFlags = 0;
  460. blend.AlphaFormat = AC_SRC_ALPHA;
  461. blend.SourceConstantAlpha = 0xFF /*DRAGDROP_ALPHA*/;
  462. HDC hdc = GetDC(_hwnd);
  463. if (hdc)
  464. {
  465. DWORD fULWType = ULW_ALPHA;
  466. // Should have been preprocess already
  467. UpdateLayeredWindow(_hwnd, hdc, &pt, &(_shdi.sizeDragImage),
  468. _hdcDragImage, &ptSrc, _shdi.crColorKey,
  469. &blend, fULWType);
  470. ReleaseDC(_hwnd, hdc);
  471. }
  472. hr = S_OK;
  473. }
  474. }
  475. else
  476. {
  477. // These are in Client Cordinates, not screen coords. Translate:
  478. POINT pt = *ppt;
  479. RECT rc;
  480. GetWindowRect(_hwndTarget, &rc);
  481. pt.x -= rc.left;
  482. pt.y -= rc.top;
  483. if (_fImage)
  484. {
  485. // Avoid the flicker by always pass even coords
  486. ImageList_DragEnter(hwndTarget, pt.x & ~1, pt.y & ~1);
  487. hr = S_OK;
  488. }
  489. else
  490. {
  491. _MultipleDragStart(hwndTarget, _parc, _cItems, pt, _ptOffset);
  492. hr = S_OK;
  493. }
  494. }
  495. //
  496. // We should always show the image whenever this function is called.
  497. //
  498. Show(TRUE);
  499. }
  500. return hr;
  501. }
  502. //
  503. // kill the Layered Window, or to stop painting the icon or rect drag images
  504. //
  505. STDMETHODIMP CDragImages::DragLeave()
  506. {
  507. TraceMsg(TF_DRAGIMAGES, "CDragImages::DragLeave");
  508. if (Initialized())
  509. {
  510. if (_hwnd)
  511. {
  512. FreeDragData();
  513. }
  514. else if (_Single.bDragging &&
  515. _Single.idThreadEntered == GetCurrentThreadId())
  516. {
  517. Show(FALSE);
  518. if (_fImage)
  519. {
  520. ImageList_DragLeave(_Single.hwndLock);
  521. }
  522. _Single.bDragging = FALSE;
  523. DAD_SetDragImage((HIMAGELIST)-1, NULL);
  524. }
  525. _ptDebounce.x = 0;
  526. _ptDebounce.y = 0;
  527. }
  528. return S_OK;
  529. }
  530. // move the Layered window or to rerender the icon or rect images within
  531. // the Window they are over.
  532. //
  533. STDMETHODIMP CDragImages::DragOver(POINT* ppt, DWORD dwEffect)
  534. {
  535. if (Initialized())
  536. {
  537. TraceMsg(TF_DRAGIMAGES, "CDragImages::DragOver pt {%d, %d}", ppt->x, ppt->y);
  538. // Avoid the flicker by always pass even coords
  539. ppt->x &= ~1;
  540. ppt->y &= ~1;
  541. if (_ptDebounce.x != ppt->x || _ptDebounce.y != ppt->y)
  542. {
  543. _ptDebounce.x = ppt->x;
  544. _ptDebounce.y = ppt->y;
  545. if (IsDraggingLayeredWindow())
  546. {
  547. POINT pt;
  548. GetCursorPos(&pt);
  549. pt.x -= _shdi.ptOffset.x;
  550. pt.y -= _shdi.ptOffset.y;
  551. SetWindowPos(_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE |
  552. SWP_NOSIZE | SWP_SHOWWINDOW);
  553. UpdateLayeredWindow(_hwnd, NULL, &pt, NULL, NULL, NULL, 0,
  554. NULL, 0);
  555. }
  556. else
  557. {
  558. // These are in Client Cordinates, not screen coords. Translate:
  559. POINT pt = *ppt;
  560. RECT rc;
  561. GetWindowRect(_hwndTarget, &rc);
  562. pt.x -= rc.left;
  563. pt.y -= rc.top;
  564. if (_fImage)
  565. {
  566. ImageList_DragMove(pt.x, pt.y);
  567. }
  568. else
  569. {
  570. _MultipleDragMove(pt);
  571. }
  572. }
  573. }
  574. }
  575. return S_OK;
  576. }
  577. // do any cleanup after a drop (Currently calls DragLeave)
  578. //
  579. STDMETHODIMP CDragImages::Drop(IDataObject* pdtobj, POINT* ppt, DWORD dwEffect)
  580. {
  581. return DragLeave();
  582. }
  583. // initialize the static drag image manager from a structure
  584. // this is implemented for WindowLess controls that can act as a
  585. // drag source.
  586. //
  587. void CDragImages::SetDragCursor(int idCursor)
  588. {
  589. //
  590. // Ignore if we are dragging over ourselves.
  591. //
  592. if (IsDraggingImage())
  593. {
  594. POINT ptHotSpot;
  595. if (_himlCursors && (idCursor != -1))
  596. {
  597. int iIndex = _MapCursorIDToImageListIndex(idCursor);
  598. if (iIndex != -1)
  599. {
  600. ImageList_GetDragImage(NULL, &ptHotSpot);
  601. ptHotSpot.x -= _aptHotSpot[idCursor].x;
  602. ptHotSpot.y -= _aptHotSpot[idCursor].y;
  603. if (ptHotSpot.x < 0)
  604. {
  605. ptHotSpot.x = 0;
  606. }
  607. if (ptHotSpot.y < 0)
  608. {
  609. ptHotSpot.y = 0;
  610. }
  611. ImageList_SetDragCursorImage(_himlCursors, iIndex, ptHotSpot.x, ptHotSpot.y);
  612. }
  613. else
  614. {
  615. // You passed a bad Cursor ID.
  616. ASSERT(0);
  617. }
  618. }
  619. _idCursor = idCursor;
  620. }
  621. }
  622. // init our state from the hGlobal so we can draw
  623. HRESULT CDragImages::_LoadLayeredBitmapBits(HGLOBAL hGlobal)
  624. {
  625. HRESULT hr = E_FAIL;
  626. if (!Initialized())
  627. {
  628. ASSERT(_shdi.hbmpDragImage == NULL);
  629. ASSERT(_hdcDragImage == NULL);
  630. HDC hdcScreen = GetDC(NULL);
  631. if (hdcScreen)
  632. {
  633. void *pvDragStuff = (void*)GlobalLock(hGlobal);
  634. if (pvDragStuff)
  635. {
  636. CopyMemory(&_shdi, pvDragStuff, sizeof(_shdi));
  637. BITMAPINFO bmi = {0};
  638. // Create a buffer to read the bits into
  639. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  640. bmi.bmiHeader.biWidth = _shdi.sizeDragImage.cx;
  641. bmi.bmiHeader.biHeight = _shdi.sizeDragImage.cy;
  642. bmi.bmiHeader.biPlanes = 1;
  643. bmi.bmiHeader.biBitCount = 32;
  644. bmi.bmiHeader.biCompression = BI_RGB;
  645. // Next create a DC and an HBITMAP.
  646. _hdcDragImage = CreateCompatibleDC(hdcScreen);
  647. if (_hdcDragImage)
  648. {
  649. void *pvBits;
  650. _shdi.hbmpDragImage = CreateDIBSection(_hdcDragImage, &bmi, DIB_RGB_COLORS, &pvBits, NULL, NULL);
  651. if (_shdi.hbmpDragImage)
  652. {
  653. _hbmpOld = (HBITMAP)SelectObject(_hdcDragImage, _shdi.hbmpDragImage);
  654. // then Set the bits into the Bitmap
  655. RGBQUAD* pvStart = (RGBQUAD*)((BYTE*)pvDragStuff + sizeof(SHDRAGIMAGE));
  656. DWORD dwCount = _shdi.sizeDragImage.cx * _shdi.sizeDragImage.cy * sizeof(RGBQUAD);
  657. CopyMemory((RGBQUAD*)pvBits, (RGBQUAD*)pvStart, dwCount);
  658. hr = S_OK; // success!
  659. }
  660. }
  661. GlobalUnlock(hGlobal);
  662. }
  663. ReleaseDC(NULL, hdcScreen);
  664. }
  665. }
  666. return hr;
  667. }
  668. // Writes the written information into phGlobal to recreate the drag image
  669. HRESULT CDragImages::_SaveLayeredBitmapBits(HGLOBAL* phGlobal)
  670. {
  671. HRESULT hr = E_FAIL;
  672. if (Initialized())
  673. {
  674. ASSERT(_shdi.hbmpDragImage);
  675. DWORD cbImageSize = _shdi.sizeDragImage.cx * _shdi.sizeDragImage.cy * sizeof(RGBQUAD);
  676. *phGlobal = GlobalAlloc(GPTR, cbImageSize + sizeof(SHDRAGIMAGE));
  677. if (*phGlobal)
  678. {
  679. void *pvDragStuff = GlobalLock(*phGlobal);
  680. CopyMemory(pvDragStuff, &_shdi, sizeof(SHDRAGIMAGE));
  681. void *pvBits;
  682. hr = _PreProcessDragBitmap(&pvBits) ? S_OK : E_FAIL;
  683. if (SUCCEEDED(hr))
  684. {
  685. RGBQUAD* pvStart = (RGBQUAD*)((BYTE*)pvDragStuff + sizeof(SHDRAGIMAGE));
  686. DWORD dwCount = _shdi.sizeDragImage.cx * _shdi.sizeDragImage.cy * sizeof(RGBQUAD);
  687. CopyMemory((RGBQUAD*)pvStart, (RGBQUAD*)pvBits, dwCount);
  688. }
  689. GlobalUnlock(*phGlobal);
  690. }
  691. }
  692. return hr;
  693. }
  694. BOOL IsColorKey(RGBQUAD rgbPixel, COLORREF crKey)
  695. {
  696. // COLORREF is backwards to RGBQUAD
  697. return InRange( rgbPixel.rgbBlue, ((crKey & 0xFF0000) >> 16) - 5, ((crKey & 0xFF0000) >> 16) + 5) &&
  698. InRange( rgbPixel.rgbGreen, ((crKey & 0x00FF00) >> 8) - 5, ((crKey & 0x00FF00) >> 8) + 5) &&
  699. InRange( rgbPixel.rgbRed, ((crKey & 0x0000FF) >> 0) - 5, ((crKey & 0x0000FF) >> 0) + 5);
  700. }
  701. #ifdef RADIAL
  702. int QuickRoot(int n, int iNum)
  703. {
  704. int iRoot = iNum;
  705. for (int i=10; i > 0; i--)
  706. {
  707. int iOld = iRoot;
  708. iRoot = (iRoot + iNum/iRoot)/2;
  709. if (iRoot == iOld)
  710. break;
  711. }
  712. return iRoot;
  713. }
  714. #endif
  715. BOOL CDragImages::_PreProcessDragBitmap(void** ppvBits)
  716. {
  717. BOOL fRet = FALSE;
  718. ASSERT(_hdcDragImage == NULL);
  719. _hdcDragImage = CreateCompatibleDC(NULL);
  720. if (_hdcDragImage)
  721. {
  722. ULONG* pul;
  723. HBITMAP hbmpResult = NULL;
  724. HBITMAP hbmpOld;
  725. HDC hdcSource = NULL;
  726. BITMAPINFO bmi = {0};
  727. HBITMAP hbmp = _shdi.hbmpDragImage;
  728. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  729. bmi.bmiHeader.biWidth = _shdi.sizeDragImage.cx;
  730. bmi.bmiHeader.biHeight = _shdi.sizeDragImage.cy;
  731. bmi.bmiHeader.biPlanes = 1;
  732. bmi.bmiHeader.biBitCount = 32;
  733. bmi.bmiHeader.biCompression = BI_RGB;
  734. hdcSource = CreateCompatibleDC(_hdcDragImage);
  735. if (hdcSource)
  736. {
  737. hbmpResult = CreateDIBSection(_hdcDragImage,
  738. &bmi,
  739. DIB_RGB_COLORS,
  740. ppvBits,
  741. NULL,
  742. 0);
  743. if (hbmpResult)
  744. {
  745. _hbmpOld = (HBITMAP)SelectObject(_hdcDragImage, hbmpResult);
  746. hbmpOld = (HBITMAP)SelectObject(hdcSource, hbmp);
  747. BitBlt(_hdcDragImage, 0, 0, _shdi.sizeDragImage.cx, _shdi.sizeDragImage.cy,
  748. hdcSource, 0, 0, SRCCOPY);
  749. pul = (ULONG*)*ppvBits;
  750. int iOffsetX = _shdi.ptOffset.x;
  751. int iOffsetY = _shdi.ptOffset.y;
  752. int iDenomX = max(_shdi.sizeDragImage.cx - iOffsetX, iOffsetX);
  753. int iDenomY = max(_shdi.sizeDragImage.cy - iOffsetY, iOffsetY);
  754. BOOL fRadialFade = TRUE;
  755. // If both are less than the max, then no radial fade.
  756. if (_shdi.sizeDragImage.cy <= MAX_HEIGHT_ALPHA && _shdi.sizeDragImage.cx <= MAX_WIDTH_ALPHA)
  757. fRadialFade = FALSE;
  758. for (int Y = 0; Y < _shdi.sizeDragImage.cy; Y++)
  759. {
  760. int y = _shdi.sizeDragImage.cy - Y; // Bottom up DIB.
  761. for (int x = 0; x < _shdi.sizeDragImage.cx; x++)
  762. {
  763. RGBQUAD* prgb = (RGBQUAD*)&pul[Y * _shdi.sizeDragImage.cx + x];
  764. if (_shdi.crColorKey != CLR_NONE &&
  765. IsColorKey(*prgb, _shdi.crColorKey))
  766. {
  767. // Write a pre-multiplied value of 0:
  768. *((DWORD*)prgb) = 0;
  769. }
  770. else
  771. {
  772. int Alpha = prgb->rgbReserved;
  773. if (_shdi.crColorKey != CLR_NONE)
  774. {
  775. Alpha = DRAGDROP_ALPHA;
  776. }
  777. else
  778. {
  779. Alpha -= (Alpha / 3);
  780. }
  781. if (fRadialFade && Alpha > 0)
  782. {
  783. // This does not generate a smooth curve, but this is just
  784. // an effect, not trying to be accurate here.
  785. // 3 devides per pixel
  786. int ddx = (x < iOffsetX)? iOffsetX - x : x - iOffsetX;
  787. int ddy = (y < iOffsetY)? iOffsetY - y : y - iOffsetY;
  788. __int64 iAlphaX = (100000l - (((__int64)ddx * 100000l) / (iDenomX )));
  789. __int64 iAlphaY = (100000l - (((__int64)ddy * 100000l) / (iDenomY )));
  790. ASSERT (iAlphaX >= 0);
  791. ASSERT (iAlphaY >= 0);
  792. __int64 iDenom = 100000;
  793. iDenom *= 100000;
  794. Alpha = (int) ((Alpha * iAlphaX * iAlphaY * 100000) / (iDenom* 141428));
  795. }
  796. ASSERT(Alpha <= 0xFF);
  797. prgb->rgbReserved = (BYTE)Alpha;
  798. prgb->rgbRed = ((prgb->rgbRed * Alpha) + 128) / 255;
  799. prgb->rgbGreen = ((prgb->rgbGreen * Alpha) + 128) / 255;
  800. prgb->rgbBlue = ((prgb->rgbBlue * Alpha) + 128) / 255;
  801. }
  802. }
  803. }
  804. DeleteObject(hbmp);
  805. _shdi.hbmpDragImage = hbmpResult;
  806. fRet = TRUE;
  807. if (hbmpOld)
  808. SelectObject(hdcSource, hbmpOld);
  809. }
  810. DeleteObject(hdcSource);
  811. }
  812. }
  813. return fRet;
  814. }
  815. CLIPFORMAT _GetDragContentsCF()
  816. {
  817. static UINT s_cfDragContents = 0;
  818. if (0 == s_cfDragContents)
  819. s_cfDragContents = RegisterClipboardFormat(CFSTR_DRAGCONTEXT);
  820. return (CLIPFORMAT) s_cfDragContents;
  821. }
  822. CLIPFORMAT _GetDragImageBitssCF()
  823. {
  824. static UINT s_cfDragImageBitss = 0;
  825. if (0 == s_cfDragImageBitss)
  826. s_cfDragImageBitss = RegisterClipboardFormat(TEXT("DragImageBits"));
  827. return (CLIPFORMAT) s_cfDragImageBitss;
  828. }
  829. // persist our state into the data object. so on the target side they can grab this
  830. // data out and render the thing being dragged
  831. HRESULT CDragImages::_SaveToDataObject(IDataObject *pdtobj)
  832. {
  833. HRESULT hr = E_FAIL; // one form of the saves below must succeed
  834. if (Initialized())
  835. {
  836. STGMEDIUM medium = {0};
  837. medium.tymed = TYMED_ISTREAM;
  838. if (SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &medium.pstm)))
  839. {
  840. // Set the header .
  841. DragContextHeader hdr = {0};
  842. hdr.fImage = _fImage;
  843. hdr.fLayered = IsDraggingLayeredWindow();
  844. hdr.ptOffset = _ptOffset;
  845. //First Write the drag context header
  846. ULONG ulWritten;
  847. if (SUCCEEDED(medium.pstm->Write(&hdr, sizeof(hdr), &ulWritten)) &&
  848. (ulWritten == sizeof(hdr)))
  849. {
  850. if (hdr.fLayered)
  851. {
  852. STGMEDIUM mediumBits = {0};
  853. // Set the medium.
  854. mediumBits.tymed = TYMED_HGLOBAL;
  855. // Write out layered window information
  856. hr = _SaveLayeredBitmapBits(&mediumBits.hGlobal);
  857. if (SUCCEEDED(hr))
  858. {
  859. FORMATETC fmte = {_GetDragImageBitssCF(), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  860. // Set the medium in the data.
  861. hr = pdtobj->SetData(&fmte, &mediumBits, TRUE);
  862. if (FAILED(hr))
  863. ReleaseStgMedium(&mediumBits); // cleanup
  864. }
  865. }
  866. else if (hdr.fImage)
  867. {
  868. // write an image
  869. HIMAGELIST himl = ImageList_GetDragImage(NULL, NULL);
  870. if (ImageList_Write(himl, medium.pstm))
  871. {
  872. hr = S_OK; // success
  873. }
  874. }
  875. else
  876. {
  877. // multi rect
  878. if (SUCCEEDED(medium.pstm->Write(&_cItems, sizeof(_cItems), &ulWritten)) &&
  879. (ulWritten == sizeof(_cItems)))
  880. {
  881. // Write the rects into the stream
  882. if (SUCCEEDED(medium.pstm->Write(_parc, sizeof(_parc[0]) * _cItems, &ulWritten)) &&
  883. (ulWritten == (sizeof(_parc[0]) * _cItems)))
  884. {
  885. hr = S_OK; // success
  886. }
  887. }
  888. }
  889. if (SUCCEEDED(hr))
  890. {
  891. // Set the seek pointer at the beginning.
  892. medium.pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  893. // Set the Formatetc
  894. FORMATETC fmte = {_GetDragContentsCF(), NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM};
  895. // Set the medium in the data.
  896. hr = pdtobj->SetData(&fmte, &medium, TRUE);
  897. }
  898. }
  899. if (FAILED(hr))
  900. ReleaseStgMedium(&medium);
  901. }
  902. }
  903. return hr;
  904. }
  905. // Gets the information to rebuild the drag images from the data object
  906. HRESULT CDragImages::_LoadFromDataObject(IDataObject *pdtobj)
  907. {
  908. // Check if we have a drag context
  909. HRESULT hr;
  910. // NULL pdtobj is for the old DAD_DragEnterXXX() APIs...
  911. // we hope this in the same process
  912. if (Initialized() || !pdtobj)
  913. {
  914. hr = S_OK; // already loaded
  915. }
  916. else
  917. {
  918. // Set the format we are interested in
  919. FORMATETC fmte = {_GetDragContentsCF(), NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM};
  920. //if the data object has the format we are interested in
  921. // then Get the data
  922. STGMEDIUM medium = {0};
  923. hr = pdtobj->GetData(&fmte, &medium);
  924. if (SUCCEEDED(hr)) // if no pstm, bag out.
  925. {
  926. // Set the seek pointer at the beginning. PARANOIA: This is for people
  927. // Who don't set the seek for me.
  928. medium.pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  929. //First Read the drag context header
  930. DragContextHeader hdr;
  931. if (SUCCEEDED(IStream_Read(medium.pstm, &hdr, sizeof(hdr))))
  932. {
  933. if (hdr.fLayered)
  934. {
  935. STGMEDIUM mediumBits;
  936. FORMATETC fmte = {_GetDragImageBitssCF(), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  937. hr = pdtobj->GetData(&fmte, &mediumBits);
  938. if (SUCCEEDED(hr))
  939. {
  940. hr = _LoadLayeredBitmapBits(mediumBits.hGlobal);
  941. ReleaseStgMedium(&mediumBits);
  942. }
  943. }
  944. else if (hdr.fImage)
  945. {
  946. // single image
  947. HIMAGELIST himl = ImageList_Read(medium.pstm);
  948. if (himl)
  949. {
  950. DAD_SetDragImage(himl, &(hdr.ptOffset));
  951. ImageList_Destroy(himl);
  952. hr = S_OK;
  953. }
  954. }
  955. else
  956. {
  957. // multi rect
  958. int cItems;
  959. if (SUCCEEDED(IStream_Read(medium.pstm, &cItems, sizeof(cItems))))
  960. {
  961. RECT *prect = (RECT *)LocalAlloc(LPTR, sizeof(*prect) * cItems);
  962. if (prect)
  963. {
  964. if (SUCCEEDED(IStream_Read(medium.pstm, prect, sizeof(*prect) * cItems)))
  965. {
  966. hr = _SetMultiRectDragging(cItems, prect, &hdr.ptOffset);
  967. }
  968. LocalFree(prect);
  969. }
  970. }
  971. }
  972. }
  973. if (SUCCEEDED(hr))
  974. _InitDragData();
  975. // Set the seek pointer at the beginning. Just cleaning up...
  976. medium.pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  977. // Release the stg medium.
  978. ReleaseStgMedium(&medium);
  979. }
  980. }
  981. return hr;
  982. }
  983. // Shows or hides the drag images. NOTE: Doesn't do anything in the layered window case.
  984. // We don't need to because this function is specifically for drawing to a locked window.
  985. STDMETHODIMP CDragImages::Show(BOOL bShow)
  986. {
  987. BOOL fOld = bShow;
  988. TraceMsg(TF_DRAGIMAGES, "CDragImages::Show(%s)", bShow? TEXT("true") : TEXT("false"));
  989. if (!Initialized() || !_Single.bDragging)
  990. {
  991. return S_FALSE;
  992. }
  993. // No point in showing and hiding a Window. This causes unnecessary flicker.
  994. if (_hwnd)
  995. {
  996. return S_OK;
  997. }
  998. // If we're going across thread boundaries we have to try a context switch
  999. if (GetCurrentThreadId() != GetWindowThreadProcessId(_Single.hwndLock, NULL) &&
  1000. _ShowDragImageInterThread(_Single.hwndLock, &fOld))
  1001. return fOld;
  1002. fOld = _Single.bLocked;
  1003. //
  1004. // If we are going to show the drag image, lock the target window.
  1005. //
  1006. if (bShow && !_Single.bLocked)
  1007. {
  1008. TraceMsg(TF_DRAGIMAGES, "CDragImages::Show : Shown and not locked");
  1009. UpdateWindow(_Single.hwndLock);
  1010. LockWindowUpdate(_Single.hwndLock);
  1011. _Single.bLocked = TRUE;
  1012. }
  1013. if (_Single.bSingle)
  1014. {
  1015. TraceMsg(TF_DRAGIMAGES, "CDragImages::Show : Calling ImageList_DragShowNoLock");
  1016. ImageList_DragShowNolock(bShow);
  1017. }
  1018. else
  1019. {
  1020. TraceMsg(TF_DRAGIMAGES, "CDragImages::Show : MultiDragShow");
  1021. _MultipleDragShow(bShow);
  1022. }
  1023. //
  1024. // If we have just hide the drag image, unlock the target window.
  1025. //
  1026. if (!bShow && _Single.bLocked)
  1027. {
  1028. TraceMsg(TF_DRAGIMAGES, "CDragImages::Show : hiding image, unlocking");
  1029. LockWindowUpdate(NULL);
  1030. _Single.bLocked = FALSE;
  1031. }
  1032. return fOld ? S_OK : S_FALSE;
  1033. }
  1034. // tell the drag source to hide or unhide the drag image to allow
  1035. // the destination to do drawing (unlock the screen)
  1036. //
  1037. // in:
  1038. // bShow FALSE - hide the drag image, allow drawing
  1039. // TRUE - show the drag image, no drawing allowed after this
  1040. // Helper function for DAD_ShowDragImage - handles the inter-thread case.
  1041. // We need to handle this case differently because LockWindowUpdate calls fail
  1042. // if they are on the wrong thread.
  1043. BOOL CDragImages::_ShowDragImageInterThread(HWND hwndLock, BOOL * pfShow)
  1044. {
  1045. TCHAR szClassName[50];
  1046. if (GetClassName(hwndLock, szClassName, ARRAYSIZE(szClassName)))
  1047. {
  1048. UINT uMsg = 0;
  1049. ULONG_PTR dw = 0;
  1050. if (lstrcmpi(szClassName, TEXT("SHELLDLL_DefView")) == 0)
  1051. uMsg = WM_DSV_SHOWDRAGIMAGE;
  1052. if (lstrcmpi(szClassName, TEXT("CabinetWClass")) == 0)
  1053. uMsg = CWM_SHOWDRAGIMAGE;
  1054. if (uMsg)
  1055. {
  1056. SendMessageTimeout(hwndLock, uMsg, 0, *pfShow, SMTO_ABORTIFHUNG, 1000, &dw);
  1057. *pfShow = (dw != 0);
  1058. return TRUE;
  1059. }
  1060. }
  1061. return FALSE;
  1062. }
  1063. void CDragImages::ThreadDetach()
  1064. {
  1065. if (_idThread == GetCurrentThreadId())
  1066. FreeDragData();
  1067. }
  1068. void CDragImages::ProcessDetach()
  1069. {
  1070. FreeDragData();
  1071. }
  1072. BOOL CDragImages::SetDragImage(HIMAGELIST himl, int index, POINT * pptOffset)
  1073. {
  1074. if (himl)
  1075. {
  1076. // We are setting
  1077. if (Initialized())
  1078. return FALSE;
  1079. _fImage = TRUE;
  1080. if (pptOffset)
  1081. {
  1082. // Avoid the flicker by always pass even coords
  1083. _ptOffset.x = (pptOffset->x & ~1);
  1084. _ptOffset.y = (pptOffset->y & ~1);
  1085. }
  1086. ImageList_BeginDrag(himl, index, _ptOffset.x, _ptOffset.y);
  1087. _InitDragData();
  1088. }
  1089. else
  1090. {
  1091. FreeDragData();
  1092. }
  1093. return TRUE;
  1094. }
  1095. //=====================================================================
  1096. // Multiple Drag show
  1097. //=====================================================================
  1098. void CDragImages::_MultipleDragShow(BOOL bShow)
  1099. {
  1100. HDC hDC;
  1101. int nRect;
  1102. RECT rc, rcClip;
  1103. if ((bShow && _Single._Multi.bShown) || (!bShow && !_Single._Multi.bShown))
  1104. return;
  1105. _Single._Multi.bShown = bShow;
  1106. // clip to window, NOT SM_CXSCREEN/SM_CYSCREEN (multiple monitors)
  1107. GetWindowRect(_Single.hwndLock, &rcClip);
  1108. rcClip.right -= rcClip.left;
  1109. rcClip.bottom -= rcClip.top;
  1110. hDC = GetDCEx(_Single.hwndLock, NULL, DCX_WINDOW | DCX_CACHE |
  1111. DCX_LOCKWINDOWUPDATE | DCX_CLIPSIBLINGS);
  1112. for (nRect = _Single._Multi.nRects - 1; nRect >= 0; --nRect)
  1113. {
  1114. rc = _Single._Multi.pRect[nRect];
  1115. OffsetRect(&rc, _Single._Multi.ptNow.x - _Single._Multi.ptOffset.x,
  1116. _Single._Multi.ptNow.y - _Single._Multi.ptOffset.y);
  1117. if ((rc.top < rcClip.bottom) && (rc.bottom > 0) &&
  1118. (rc.left < rcClip.right) && (rc.right > 0))
  1119. {
  1120. DrawFocusRect(hDC, &rc);
  1121. }
  1122. }
  1123. ReleaseDC(_Single.hwndLock, hDC);
  1124. }
  1125. void CDragImages::_MultipleDragStart(HWND hwndLock, LPRECT aRect, int nRects, POINT ptStart, POINT ptOffset)
  1126. {
  1127. _Single._Multi.bShown = FALSE;
  1128. _Single._Multi.pRect = aRect;
  1129. _Single._Multi.nRects = nRects;
  1130. _Single._Multi.ptOffset = ptOffset;
  1131. _Single._Multi.ptNow = ptStart;
  1132. }
  1133. void CDragImages::_MultipleDragMove(POINT ptNew)
  1134. {
  1135. if ((_Single._Multi.ptNow.x == ptNew.x) &&
  1136. (_Single._Multi.ptNow.y == ptNew.y))
  1137. {
  1138. // nothing has changed. bail
  1139. return;
  1140. }
  1141. if (_Single._Multi.bShown)
  1142. {
  1143. HDC hDC;
  1144. int nRect;
  1145. RECT rc, rcClip;
  1146. int dx1 = _Single._Multi.ptNow.x - _Single._Multi.ptOffset.x;
  1147. int dy1 = _Single._Multi.ptNow.y - _Single._Multi.ptOffset.y;
  1148. int dx2 = ptNew.x - _Single._Multi.ptNow.x;
  1149. int dy2 = ptNew.y - _Single._Multi.ptNow.y;
  1150. // clip to window, NOT SM_CXSCREEN/SM_CYSCREEN (multiple monitors)
  1151. GetWindowRect(_Single.hwndLock, &rcClip);
  1152. rcClip.right -= rcClip.left;
  1153. rcClip.bottom -= rcClip.top;
  1154. hDC = GetDCEx(_Single.hwndLock, NULL, DCX_WINDOW | DCX_CACHE |
  1155. DCX_LOCKWINDOWUPDATE | DCX_CLIPSIBLINGS);
  1156. for (nRect = _Single._Multi.nRects - 1; nRect >= 0; --nRect)
  1157. {
  1158. rc = _Single._Multi.pRect[nRect];
  1159. // hide pass
  1160. OffsetRect(&rc, dx1, dy1);
  1161. if ((rc.top < rcClip.bottom) && (rc.bottom > 0) &&
  1162. (rc.left < rcClip.right) && (rc.right > 0))
  1163. {
  1164. DrawFocusRect(hDC, &rc);
  1165. }
  1166. // show pass
  1167. OffsetRect(&rc, dx2, dy2);
  1168. if ((rc.top < rcClip.bottom) && (rc.bottom > 0) &&
  1169. (rc.left < rcClip.right) && (rc.right > 0))
  1170. {
  1171. DrawFocusRect(hDC, &rc);
  1172. }
  1173. }
  1174. ReleaseDC(_Single.hwndLock, hDC);
  1175. }
  1176. _Single._Multi.ptNow = ptNew;
  1177. }
  1178. HRESULT CDragImages::_SetMultiRectDragging(int cItems, LPRECT prect, POINT *pptOffset)
  1179. {
  1180. if (!Initialized())
  1181. {
  1182. // Multiple item drag
  1183. _cItems = cItems;
  1184. _parc = new RECT[2 * _cItems];
  1185. if (_parc)
  1186. {
  1187. for (int i = 0; i < cItems; i++)
  1188. _parc[i] = prect[i];
  1189. // Avoid the flicker by always pass even coords
  1190. _ptOffset.x = (pptOffset->x & ~1);
  1191. _ptOffset.y = (pptOffset->y & ~1);
  1192. _InitDragData();
  1193. }
  1194. }
  1195. return S_OK;
  1196. }
  1197. #define ListView_IsIconView(hwndLV) ((GetWindowLong(hwndLV, GWL_STYLE) & (UINT)LVS_TYPEMASK) == (UINT)LVS_ICON)
  1198. HRESULT CDragImages::_SetMultiItemDragging(HWND hwndLV, int cItems, POINT *pptOffset)
  1199. {
  1200. HRESULT hr = E_FAIL;
  1201. if (!Initialized())
  1202. {
  1203. // Multiple item drag
  1204. ASSERT(NULL == _parc);
  1205. _parc = new RECT[2 * cItems];
  1206. if (_parc)
  1207. {
  1208. POINT ptTemp;
  1209. int iLast, iNext;
  1210. int cxScreens, cyScreens;
  1211. LPRECT prcNext;
  1212. RECT rc;
  1213. _cItems = 0;
  1214. ASSERT(_fImage == FALSE);
  1215. //
  1216. // If this is a mirrored Window, then lead edge is going
  1217. // to be the far end in screen coord. So let's compute
  1218. // as the original code, and later in _MultipleDragMove
  1219. // we will compensate.
  1220. //
  1221. GetWindowRect( hwndLV , &rc );
  1222. ptTemp.x = rc.left;
  1223. ptTemp.y = rc.top;
  1224. //
  1225. // Reflect the shift the if the window is RTL mirrored.
  1226. //
  1227. if (IS_WINDOW_RTL_MIRRORED(hwndLV))
  1228. {
  1229. ptTemp.x = -ptTemp.x;
  1230. pptOffset->x = ((rc.right-rc.left)-pptOffset->x);
  1231. }
  1232. cxScreens = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  1233. cyScreens = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  1234. // for pre-Nashville platforms
  1235. if (!cxScreens || !cyScreens)
  1236. {
  1237. cxScreens = GetSystemMetrics(SM_CXSCREEN);
  1238. cyScreens = GetSystemMetrics(SM_CYSCREEN);
  1239. }
  1240. for (iNext = cItems - 1, iLast = -1, prcNext = _parc; iNext >= 0; --iNext)
  1241. {
  1242. iLast = ListView_GetNextItem(hwndLV, iLast, LVNI_SELECTED);
  1243. if (iLast != -1)
  1244. {
  1245. ListView_GetItemRect(hwndLV, iLast, &prcNext[0], LVIR_ICON);
  1246. OffsetRect(&prcNext[0], ptTemp.x, ptTemp.y);
  1247. if (((prcNext[0].left - pptOffset->x) < cxScreens) &&
  1248. ((pptOffset->x - prcNext[0].right) < cxScreens) &&
  1249. ((prcNext[0].top - pptOffset->y) < cyScreens))
  1250. {
  1251. ListView_GetItemRect(hwndLV, iLast, &prcNext[1], LVIR_LABEL);
  1252. OffsetRect(&prcNext[1], ptTemp.x, ptTemp.y);
  1253. if ((pptOffset->y - prcNext[1].bottom) < cxScreens)
  1254. {
  1255. //
  1256. // Fix 24857: Ask JoeB why we are drawing a bar instead of
  1257. // a text rectangle.
  1258. //
  1259. prcNext[1].top = (prcNext[1].top + prcNext[1].bottom)/2;
  1260. prcNext[1].bottom = prcNext[1].top + 2;
  1261. prcNext += 2;
  1262. _cItems += 2;
  1263. }
  1264. }
  1265. }
  1266. }
  1267. // Avoid the flicker by always pass even coords
  1268. _ptOffset.x = (pptOffset->x & ~1);
  1269. _ptOffset.y = (pptOffset->y & ~1);
  1270. _InitDragData();
  1271. hr = S_OK;
  1272. }
  1273. }
  1274. return hr;
  1275. }
  1276. //=====================================================================
  1277. // Cursor Merging
  1278. //=====================================================================
  1279. void CDragImages::_DestroyCachedCursors()
  1280. {
  1281. if (_himlCursors)
  1282. {
  1283. ImageList_Destroy(_himlCursors);
  1284. _himlCursors = NULL;
  1285. }
  1286. HCURSOR hcursor = GetCursor();
  1287. for (int i = 0; i < ARRAYSIZE(_ahcur); i++)
  1288. {
  1289. if (_ahcur[i])
  1290. {
  1291. if (_ahcur[i] == hcursor)
  1292. {
  1293. //
  1294. // Stuff in some random cursor so that we don't try to
  1295. // destroy the current cursor (and leak it too).
  1296. //
  1297. SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));
  1298. }
  1299. DestroyCursor(_ahcur[i]);
  1300. _ahcur[i] = NULL;
  1301. }
  1302. }
  1303. }
  1304. HBITMAP CDragImages::CreateColorBitmap(int cx, int cy)
  1305. {
  1306. HDC hdc = GetDC(NULL);
  1307. HBITMAP hbm = CreateCompatibleBitmap(hdc, cx, cy);
  1308. ReleaseDC(NULL, hdc);
  1309. return hbm;
  1310. }
  1311. #define CreateMonoBitmap( cx, cy) CreateBitmap(cx, cy, 1, 1, NULL)
  1312. typedef WORD CURMASK;
  1313. #define _BitSizeOf(x) (sizeof(x)*8)
  1314. HRESULT CDragImages::_GetCursorLowerRight(HCURSOR hcursor, int * px, int * py, POINT *pptHotSpot)
  1315. {
  1316. ICONINFO iconinfo;
  1317. HRESULT hr = E_FAIL;
  1318. if (GetIconInfo(hcursor, &iconinfo))
  1319. {
  1320. CURMASK CurMask[16*8];
  1321. BITMAP bm;
  1322. int i;
  1323. int xFine = 16;
  1324. GetObject(iconinfo.hbmMask, sizeof(bm), (LPTSTR)&bm);
  1325. GetBitmapBits(iconinfo.hbmMask, sizeof(CurMask), CurMask);
  1326. pptHotSpot->x = iconinfo.xHotspot;
  1327. pptHotSpot->y = iconinfo.yHotspot;
  1328. if (iconinfo.hbmColor)
  1329. {
  1330. i = (int)(bm.bmWidth * bm.bmHeight / _BitSizeOf(CURMASK) - 1);
  1331. }
  1332. else
  1333. {
  1334. i = (int)(bm.bmWidth * (bm.bmHeight/2) / _BitSizeOf(CURMASK) - 1);
  1335. }
  1336. if ( i >= sizeof(CurMask))
  1337. {
  1338. i = sizeof(CurMask) -1;
  1339. }
  1340. // this assumes that the first pixel encountered on this bottom
  1341. // up/right to left search will be reasonably close to the rightmost pixel
  1342. // which for all of our cursors is correct, but it not necessarly correct.
  1343. // also, it assumes the cursor has a good mask... not like the IBeam XOR only
  1344. // cursor
  1345. for (; i >= 0; i--)
  1346. {
  1347. if (CurMask[i] != 0xFFFF)
  1348. {
  1349. // this is only accurate to 16 pixels... which is a big gap..
  1350. // so let's try to be a bit more accurate.
  1351. int j;
  1352. DWORD dwMask;
  1353. for (j = 0; j < 16; j++, xFine--)
  1354. {
  1355. if (j < 8)
  1356. {
  1357. dwMask = (1 << (8 + j));
  1358. }
  1359. else
  1360. {
  1361. dwMask = (1 << (j - 8));
  1362. }
  1363. if (!(CurMask[i] & dwMask))
  1364. break;
  1365. }
  1366. ASSERT(j < 16);
  1367. break;
  1368. }
  1369. }
  1370. if (iconinfo.hbmColor)
  1371. {
  1372. DeleteObject(iconinfo.hbmColor);
  1373. }
  1374. if (iconinfo.hbmMask)
  1375. {
  1376. DeleteObject(iconinfo.hbmMask);
  1377. }
  1378. // Compute the pointer height
  1379. // use width in both directions because the cursor is square, but the
  1380. // height might be doubleheight if it's mono
  1381. *py = ((i + 1) * _BitSizeOf(CURMASK)) / (int)bm.bmWidth;
  1382. *px = ((i * _BitSizeOf(CURMASK)) % (int)bm.bmWidth) + xFine + 2; // hang it off a little
  1383. hr = S_OK;
  1384. }
  1385. return hr;
  1386. }
  1387. // this will draw iiMerge's image over iiMain on main's lower right.
  1388. BOOL CDragImages::_MergeIcons(HCURSOR hcursor, LPCTSTR idMerge, HBITMAP *phbmImage, HBITMAP *phbmMask, POINT* pptHotSpot)
  1389. {
  1390. *phbmImage = NULL;
  1391. *phbmMask = NULL;
  1392. BOOL fRet = FALSE;
  1393. int xDraw;
  1394. int yDraw;
  1395. // find the lower corner of the cursor and put it there.
  1396. // do this whether or not we have an idMerge because it will set the hotspot
  1397. if (SUCCEEDED(_GetCursorLowerRight(hcursor, &xDraw, &yDraw, pptHotSpot)))
  1398. {
  1399. int xBitmap;
  1400. int yBitmap;
  1401. int xCursor = GetSystemMetrics(SM_CXCURSOR);
  1402. int yCursor = GetSystemMetrics(SM_CYCURSOR);
  1403. HBITMAP hbmp;
  1404. if (idMerge != (LPCTSTR)-1)
  1405. {
  1406. hbmp = (HBITMAP)LoadImage(HINST_THISDLL, idMerge, IMAGE_BITMAP, 0, 0, 0);
  1407. if (hbmp)
  1408. {
  1409. BITMAP bm;
  1410. GetObject(hbmp, sizeof(bm), &bm);
  1411. xBitmap = bm.bmWidth;
  1412. yBitmap = bm.bmHeight/2;
  1413. if (xDraw + xBitmap > xCursor)
  1414. xDraw = xCursor - xBitmap;
  1415. if (yDraw + yBitmap > yCursor)
  1416. yDraw = yCursor - yBitmap;
  1417. }
  1418. }
  1419. else
  1420. hbmp = NULL;
  1421. HDC hdcCursor = CreateCompatibleDC(NULL);
  1422. HBITMAP hbmMask = CreateMonoBitmap(xCursor, yCursor);
  1423. HBITMAP hbmImage = CreateColorBitmap(xCursor, yCursor);
  1424. if (hdcCursor && hbmMask && hbmImage)
  1425. {
  1426. HBITMAP hbmTemp = (HBITMAP)SelectObject(hdcCursor, hbmImage);
  1427. DrawIconEx(hdcCursor, 0, 0, hcursor, 0, 0, 0, NULL, DI_NORMAL);
  1428. HDC hdcBitmap;
  1429. if (hbmp)
  1430. {
  1431. hdcBitmap = CreateCompatibleDC(NULL);
  1432. SelectObject(hdcBitmap, hbmp);
  1433. //blt the two bitmaps onto the color and mask bitmaps for the cursor
  1434. BitBlt(hdcCursor, xDraw, yDraw, xBitmap, yBitmap, hdcBitmap, 0, 0, SRCCOPY);
  1435. }
  1436. SelectObject(hdcCursor, hbmMask);
  1437. DrawIconEx(hdcCursor, 0, 0, hcursor, 0, 0, 0, NULL, DI_MASK);
  1438. if (hbmp)
  1439. {
  1440. BitBlt(hdcCursor, xDraw, yDraw, xBitmap, yBitmap, hdcBitmap, 0, yBitmap, SRCCOPY);
  1441. // select back in the old bitmaps
  1442. SelectObject(hdcBitmap, hbmTemp);
  1443. DeleteDC(hdcBitmap);
  1444. DeleteObject(hbmp);
  1445. }
  1446. // select back in the old bitmaps
  1447. SelectObject(hdcCursor, hbmTemp);
  1448. }
  1449. if (hdcCursor)
  1450. DeleteDC(hdcCursor);
  1451. *phbmImage = hbmImage;
  1452. *phbmMask = hbmMask;
  1453. fRet = (hbmImage && hbmMask);
  1454. }
  1455. return fRet;
  1456. }
  1457. // this will take a cursor index and load
  1458. int CDragImages::_AddCursorToImageList(HCURSOR hcur, LPCTSTR idMerge, POINT *pptHotSpot)
  1459. {
  1460. int iIndex;
  1461. HBITMAP hbmImage, hbmMask;
  1462. // merge in the plus or link arrow if it's specified
  1463. if (_MergeIcons(hcur, idMerge, &hbmImage, &hbmMask, pptHotSpot))
  1464. {
  1465. iIndex = ImageList_Add(_himlCursors, hbmImage, hbmMask);
  1466. }
  1467. else
  1468. {
  1469. iIndex = -1;
  1470. }
  1471. if (hbmImage)
  1472. DeleteObject(hbmImage);
  1473. if (hbmMask)
  1474. DeleteObject(hbmMask);
  1475. return iIndex;
  1476. }
  1477. int _MapEffectToId(DWORD dwEffect)
  1478. {
  1479. int idCursor;
  1480. // DebugMsg(DM_TRACE, "sh TR - DAD_GiveFeedBack dwEffect=%x", dwEffect);
  1481. switch (dwEffect & (DROPEFFECT_COPY|DROPEFFECT_LINK|DROPEFFECT_MOVE))
  1482. {
  1483. case 0:
  1484. idCursor = DCID_NO;
  1485. break;
  1486. case DROPEFFECT_COPY:
  1487. idCursor = DCID_COPY;
  1488. break;
  1489. case DROPEFFECT_LINK:
  1490. idCursor = DCID_LINK;
  1491. break;
  1492. case DROPEFFECT_MOVE:
  1493. idCursor = DCID_MOVE;
  1494. break;
  1495. default:
  1496. // if it's a right drag, we can have any effect... we'll
  1497. // default to the arrow without merging in anything
  1498. idCursor = DCID_MOVE;
  1499. break;
  1500. }
  1501. return idCursor;
  1502. }
  1503. int CDragImages::_MapCursorIDToImageListIndex(int idCur)
  1504. {
  1505. const static struct
  1506. {
  1507. BOOL fSystem;
  1508. LPCTSTR idRes;
  1509. LPCTSTR idMerge;
  1510. }
  1511. c_acurmap[DCID_MAX] =
  1512. {
  1513. { FALSE, MAKEINTRESOURCE(IDC_NULL), (LPCTSTR)-1},
  1514. { TRUE, IDC_NO, (LPCTSTR)-1 },
  1515. { TRUE, IDC_ARROW, (LPCTSTR)-1 },
  1516. { TRUE, IDC_ARROW, MAKEINTRESOURCE(IDB_PLUS_MERGE) },
  1517. { TRUE, IDC_ARROW, MAKEINTRESOURCE(IDB_LINK_MERGE) },
  1518. };
  1519. ASSERT(idCur >= -1 && idCur < (int)ARRAYSIZE(c_acurmap));
  1520. // -1 means "Initialize the image list index array".
  1521. if (idCur == -1)
  1522. {
  1523. for (int i = 0; i < ARRAYSIZE(c_acurmap); i++)
  1524. {
  1525. _aindex[i] = -1;
  1526. }
  1527. idCur = 0; // fall through to return -1
  1528. }
  1529. else
  1530. {
  1531. if (_aindex[idCur] == -1)
  1532. {
  1533. HINSTANCE hinst = c_acurmap[idCur].fSystem ? NULL : HINST_THISDLL;
  1534. HCURSOR hcur = LoadCursor(hinst, c_acurmap[idCur].idRes);
  1535. if (hcur)
  1536. {
  1537. _aindex[idCur] = _AddCursorToImageList(hcur, c_acurmap[idCur].idMerge, &_aptHotSpot[idCur]);
  1538. }
  1539. }
  1540. }
  1541. return _aindex[idCur];
  1542. }
  1543. HCURSOR CDragImages::_SetCursorHotspot(HCURSOR hcur, POINT *ptHot)
  1544. {
  1545. ICONINFO iconinfo = { 0 };
  1546. HCURSOR hcurHotspot;
  1547. GetIconInfo(hcur, &iconinfo);
  1548. iconinfo.xHotspot = ptHot->x;
  1549. iconinfo.yHotspot = ptHot->y;
  1550. iconinfo.fIcon = FALSE;
  1551. hcurHotspot = (HCURSOR)CreateIconIndirect(&iconinfo);
  1552. if (iconinfo.hbmColor)
  1553. {
  1554. DeleteObject(iconinfo.hbmColor);
  1555. }
  1556. if (iconinfo.hbmMask)
  1557. {
  1558. DeleteObject(iconinfo.hbmMask);
  1559. }
  1560. return hcurHotspot;
  1561. }
  1562. void CDragImages::SetDropEffectCursor(int idCur)
  1563. {
  1564. if (_himlCursors && (idCur != -1))
  1565. {
  1566. if (!_ahcur[idCur])
  1567. {
  1568. int iIndex = _MapCursorIDToImageListIndex(idCur);
  1569. if (iIndex != -1)
  1570. {
  1571. HCURSOR hcurColor = ImageList_GetIcon(_himlCursors, iIndex, 0);
  1572. //
  1573. // On non C1_COLORCURSOR displays, CopyImage() will enforce
  1574. // monochrome. So on color cursor displays, we'll get colored
  1575. // dragdrop pix.
  1576. //
  1577. HCURSOR hcurScreen = (HCURSOR)CopyImage(hcurColor, IMAGE_CURSOR,
  1578. 0, 0, LR_COPYRETURNORG | LR_DEFAULTSIZE);
  1579. HCURSOR hcurFinal = _SetCursorHotspot(hcurScreen, &_aptHotSpot[idCur]);
  1580. if ((hcurScreen != hcurColor) && hcurColor)
  1581. {
  1582. DestroyCursor(hcurColor);
  1583. }
  1584. if (hcurFinal)
  1585. {
  1586. if (hcurScreen)
  1587. {
  1588. DestroyCursor(hcurScreen);
  1589. }
  1590. }
  1591. else
  1592. {
  1593. hcurFinal = hcurScreen;
  1594. }
  1595. _ahcur[idCur] = hcurFinal;
  1596. }
  1597. }
  1598. if (_ahcur[idCur])
  1599. {
  1600. //
  1601. // This code assumes that SetCursor is pretty quick if it is
  1602. // already set.
  1603. //
  1604. SetCursor(_ahcur[idCur]);
  1605. }
  1606. }
  1607. }
  1608. //=====================================================================
  1609. // CDropSource
  1610. //=====================================================================
  1611. class CDropSource : public IDropSource
  1612. {
  1613. private:
  1614. LONG _cRef;
  1615. DWORD _grfInitialKeyState;
  1616. IDataObject* _pdtobj;
  1617. public:
  1618. explicit CDropSource(IDataObject *pdtobj);
  1619. virtual ~CDropSource();
  1620. // IUnknown methods
  1621. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  1622. STDMETHODIMP_(ULONG) AddRef();
  1623. STDMETHODIMP_(ULONG) Release();
  1624. // IDropSource methods
  1625. STDMETHODIMP GiveFeedback(DWORD dwEffect);
  1626. STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
  1627. };
  1628. void DAD_ShowCursor(BOOL fShow)
  1629. {
  1630. static BOOL s_fCursorHidden = FALSE;
  1631. if (fShow)
  1632. {
  1633. if (s_fCursorHidden)
  1634. {
  1635. ShowCursor(TRUE);
  1636. s_fCursorHidden = FALSE;
  1637. }
  1638. }
  1639. else
  1640. {
  1641. if (!s_fCursorHidden)
  1642. {
  1643. ShowCursor(FALSE);
  1644. s_fCursorHidden = TRUE;
  1645. }
  1646. }
  1647. }
  1648. CDropSource::CDropSource(IDataObject *pdtobj) : _cRef(1), _pdtobj(pdtobj), _grfInitialKeyState(0)
  1649. {
  1650. _pdtobj->AddRef();
  1651. // Tell the data object that we're entering the drag loop.
  1652. DataObj_SetDWORD(_pdtobj, g_cfInDragLoop, 1);
  1653. }
  1654. CDropSource::~CDropSource()
  1655. {
  1656. DAD_ShowCursor(TRUE); // just in case
  1657. _pdtobj->Release();
  1658. }
  1659. //
  1660. // Create an instance of CDropSource
  1661. //
  1662. STDMETHODIMP CDropSource_CreateInstance(IDropSource **ppdsrc, IDataObject *pdtobj)
  1663. {
  1664. *ppdsrc = new CDropSource(pdtobj);
  1665. return *ppdsrc ? S_OK : E_OUTOFMEMORY;
  1666. }
  1667. STDMETHODIMP CDropSource::QueryInterface(REFIID riid, void **ppvObj)
  1668. {
  1669. static const QITAB qit[] = {
  1670. QITABENT(CDropSource, IDropSource),
  1671. { 0 },
  1672. };
  1673. return QISearch(this, qit, riid, ppvObj);
  1674. }
  1675. STDMETHODIMP_(ULONG) CDropSource::AddRef()
  1676. {
  1677. return InterlockedIncrement(&_cRef);
  1678. }
  1679. STDMETHODIMP_(ULONG) CDropSource::Release()
  1680. {
  1681. ASSERT( 0 != _cRef );
  1682. ULONG cRef = InterlockedDecrement(&_cRef);
  1683. if ( 0 == cRef )
  1684. {
  1685. delete this;
  1686. }
  1687. return cRef;
  1688. }
  1689. STDMETHODIMP CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
  1690. {
  1691. HRESULT hr = S_OK;
  1692. if (fEscapePressed)
  1693. {
  1694. hr = DRAGDROP_S_CANCEL;
  1695. }
  1696. else
  1697. {
  1698. // initialize ourself with the drag begin button
  1699. if (_grfInitialKeyState == 0)
  1700. _grfInitialKeyState = (grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON));
  1701. // If the window is hung for a while, the drag operation can happen before
  1702. // the first call to this function, so grfInitialKeyState will be 0. If this
  1703. // happened, then we did a drop. No need to assert...
  1704. //ASSERT(this->grfInitialKeyState);
  1705. if (!(grfKeyState & _grfInitialKeyState))
  1706. {
  1707. //
  1708. // A button is released.
  1709. //
  1710. hr = DRAGDROP_S_DROP;
  1711. }
  1712. else if (_grfInitialKeyState != (grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)))
  1713. {
  1714. //
  1715. // If the button state is changed (except the drop case, which we handle
  1716. // above, cancel the drag&drop.
  1717. //
  1718. hr = DRAGDROP_S_CANCEL;
  1719. }
  1720. }
  1721. if (hr != S_OK)
  1722. {
  1723. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1724. DAD_ShowCursor(TRUE);
  1725. DAD_SetDragCursor(DCID_NULL);
  1726. // Tell the data object that we're leaving the drag loop.
  1727. if (_pdtobj)
  1728. DataObj_SetDWORD(_pdtobj, g_cfInDragLoop, 0);
  1729. }
  1730. return hr;
  1731. }
  1732. STDMETHODIMP CDropSource::GiveFeedback(DWORD dwEffect)
  1733. {
  1734. int idCursor = _MapEffectToId(dwEffect);
  1735. //
  1736. // OLE does not give us DROPEFFECT_MOVE even though our IDT::DragOver
  1737. // returns it, if we haven't set that bit when we have called DoDragDrop.
  1738. // Instead of arguing whether or not this is a bug or by-design of OLE,
  1739. // we work around it. It is important to note that this hack around
  1740. // g_fDraggingOverSource is purely visual hack. It won't affect the
  1741. // actual drag&drop operations at all (DV_AlterEffect does it all).
  1742. //
  1743. // - SatoNa
  1744. //
  1745. if (idCursor == DCID_NO && g_fDraggingOverSource)
  1746. {
  1747. idCursor = DCID_MOVE;
  1748. }
  1749. //
  1750. // No need to merge the cursor, if we are not dragging over to
  1751. // one of shell windows.
  1752. //
  1753. if (DAD_IsDraggingImage())
  1754. {
  1755. // Feedback for single (image) dragging
  1756. DAD_ShowCursor(FALSE);
  1757. DAD_SetDragCursor(idCursor);
  1758. }
  1759. else if (DAD_IsDragging() && g_pdiDragImages)
  1760. {
  1761. // Feedback for multiple (rectangles) dragging
  1762. g_pdiDragImages->SetDropEffectCursor(idCursor);
  1763. DAD_ShowCursor(TRUE);
  1764. return NOERROR;
  1765. }
  1766. else
  1767. {
  1768. DAD_ShowCursor(TRUE);
  1769. }
  1770. return DRAGDROP_S_USEDEFAULTCURSORS;
  1771. }
  1772. //=====================================================================
  1773. // DAD
  1774. //=====================================================================
  1775. void FixupDragPoint(HWND hwnd, POINT* ppt)
  1776. {
  1777. if (hwnd)
  1778. {
  1779. RECT rc = {0};
  1780. GetWindowRect(hwnd, &rc);
  1781. ppt->x += rc.left;
  1782. ppt->y += rc.top;
  1783. }
  1784. }
  1785. BOOL DAD_InitDragImages()
  1786. {
  1787. if (!g_pdiDragImages)
  1788. CDragImages_CreateInstance(NULL, IID_IDragSourceHelper, NULL);
  1789. return g_pdiDragImages != NULL;
  1790. }
  1791. STDAPI_(BOOL) DAD_ShowDragImage(BOOL bShow)
  1792. {
  1793. if (DAD_InitDragImages())
  1794. return g_pdiDragImages->Show(bShow) == S_OK ? TRUE : FALSE;
  1795. return FALSE;
  1796. }
  1797. BOOL DAD_IsDragging()
  1798. {
  1799. if (DAD_InitDragImages())
  1800. return g_pdiDragImages->IsDragging();
  1801. return FALSE;
  1802. }
  1803. void DAD_SetDragCursor(int idCursor)
  1804. {
  1805. if (DAD_InitDragImages())
  1806. g_pdiDragImages->SetDragCursor(idCursor);
  1807. }
  1808. STDAPI_(BOOL) DAD_DragEnterEx3(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtobj)
  1809. {
  1810. RECT rc;
  1811. GetWindowRect(hwndTarget, &rc);
  1812. // If hwndTarget is RTL mirrored, then measure the
  1813. // the client point from the visual right edge
  1814. // (near edge in RTL mirrored windows). [samera]
  1815. POINT pt;
  1816. if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  1817. pt.x = rc.right - ptStart.x;
  1818. else
  1819. pt.x = ptStart.x - rc.left;
  1820. pt.y = ptStart.y - rc.top;
  1821. return DAD_DragEnterEx2(hwndTarget, pt, pdtobj);
  1822. }
  1823. STDAPI_(BOOL) DAD_DragEnterEx2(HWND hwndTarget, const POINT ptStart, IDataObject *pdtobj)
  1824. {
  1825. BOOL bRet = FALSE;
  1826. if (DAD_InitDragImages())
  1827. {
  1828. POINT pt = ptStart;
  1829. FixupDragPoint(hwndTarget, &pt);
  1830. bRet = SUCCEEDED(g_pdiDragImages->DragEnter(hwndTarget, pdtobj, &pt, NULL));
  1831. }
  1832. return bRet;
  1833. }
  1834. STDAPI_(BOOL) DAD_DragEnterEx(HWND hwndTarget, const POINT ptStart)
  1835. {
  1836. return DAD_DragEnterEx2(hwndTarget, ptStart, NULL);
  1837. }
  1838. STDAPI_(BOOL) DAD_DragEnter(HWND hwndTarget)
  1839. {
  1840. POINT ptStart;
  1841. GetCursorPos(&ptStart);
  1842. if (hwndTarget)
  1843. ScreenToClient(hwndTarget, &ptStart);
  1844. return DAD_DragEnterEx(hwndTarget, ptStart);
  1845. }
  1846. STDAPI_(BOOL) DAD_DragMoveEx(HWND hwndTarget, const POINTL ptStart)
  1847. {
  1848. RECT rc;
  1849. GetWindowRect(hwndTarget, &rc);
  1850. // If hwndTarget is RTL mirrored, then measure the
  1851. // the client point from the visual right edge
  1852. // (near edge in RTL mirrored windows). [samera]
  1853. POINT pt;
  1854. if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  1855. pt.x = rc.right - ptStart.x;
  1856. else
  1857. pt.x = ptStart.x - rc.left;
  1858. pt.y = ptStart.y - rc.top;
  1859. return DAD_DragMove(pt);
  1860. }
  1861. STDAPI_(BOOL) DAD_DragMove(POINT pt)
  1862. {
  1863. if (DAD_InitDragImages())
  1864. {
  1865. FixupDragPoint(g_pdiDragImages->GetTarget(), &pt);
  1866. return g_pdiDragImages->DragOver(&pt, 0);
  1867. }
  1868. return FALSE;
  1869. }
  1870. STDAPI_(BOOL) DAD_SetDragImage(HIMAGELIST him, POINT *pptOffset)
  1871. {
  1872. if (DAD_InitDragImages() && !g_pdiDragImages->IsDraggingLayeredWindow())
  1873. {
  1874. //
  1875. // DAD_SetDragImage(-1, NULL) means "clear the drag image only
  1876. // if the image is set by this thread"
  1877. //
  1878. if (him == (HIMAGELIST)-1)
  1879. {
  1880. BOOL fThisThreadHasImage = FALSE;
  1881. ENTERCRITICAL;
  1882. if (g_pdiDragImages->Initialized() && g_pdiDragImages->GetThread() == GetCurrentThreadId())
  1883. {
  1884. fThisThreadHasImage = TRUE;
  1885. }
  1886. LEAVECRITICAL;
  1887. if (fThisThreadHasImage)
  1888. {
  1889. g_pdiDragImages->FreeDragData();
  1890. return TRUE;
  1891. }
  1892. return FALSE;
  1893. }
  1894. return g_pdiDragImages->SetDragImage(him, 0, pptOffset);
  1895. }
  1896. return TRUE;
  1897. }
  1898. //
  1899. // This function returns TRUE, if we are dragging an image. It means
  1900. // you have called either DAD_SetDragImage (with him != NULL) or
  1901. // DAD_SetDragImageFromListview.
  1902. //
  1903. BOOL DAD_IsDraggingImage(void)
  1904. {
  1905. if (DAD_InitDragImages())
  1906. return g_pdiDragImages->IsDraggingImage();
  1907. return FALSE;
  1908. }
  1909. STDAPI_(BOOL) DAD_DragLeave()
  1910. {
  1911. if (DAD_InitDragImages())
  1912. return g_pdiDragImages->DragLeave();
  1913. return FALSE;
  1914. }
  1915. STDAPI_(void) DAD_ProcessDetach(void)
  1916. {
  1917. if (g_pdiDragImages)
  1918. {
  1919. g_pdiDragImages->ProcessDetach();
  1920. g_pdiDragImages->Release();
  1921. }
  1922. }
  1923. STDAPI_(void) DAD_ThreadDetach(void)
  1924. {
  1925. if (g_pdiDragImages)
  1926. g_pdiDragImages->ThreadDetach();
  1927. }
  1928. // called from defview on SPI_SETCURSORS (user changed the system cursors)
  1929. STDAPI_(void) DAD_InvalidateCursors(void)
  1930. {
  1931. g_cRev++;
  1932. }
  1933. STDAPI_(BOOL) DAD_SetDragImageFromWindow(HWND hwnd, POINT* ppt, IDataObject* pdtobj)
  1934. {
  1935. if (DAD_InitDragImages())
  1936. return S_OK == g_pdiDragImages->InitializeFromWindow(hwnd, ppt, pdtobj);
  1937. return FALSE;
  1938. }
  1939. // shell32.dll export, but only used by print queue window code
  1940. //
  1941. STDAPI_(BOOL) DAD_SetDragImageFromListView(HWND hwndLV, POINT ptOffset)
  1942. {
  1943. // really a nop, as this does not have access to the data object
  1944. return DAD_InitDragImages();
  1945. }
  1946. // wrapper around OLE DoDragDrop(), will create drag source on demand and supports
  1947. // drag images for you
  1948. STDAPI SHDoDragDrop(HWND hwnd, IDataObject *pdtobj, IDropSource *pdsrc, DWORD dwEffect, DWORD *pdwEffect)
  1949. {
  1950. IDropSource *pdsrcRelease = NULL;
  1951. if (pdsrc == NULL)
  1952. {
  1953. CDropSource_CreateInstance(&pdsrcRelease, pdtobj);
  1954. pdsrc = pdsrcRelease;
  1955. }
  1956. // if there is no drag contents clipboard format present, try to add it
  1957. FORMATETC fmte = {_GetDragContentsCF(), NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM};
  1958. if (S_OK != pdtobj->QueryGetData(&fmte))
  1959. {
  1960. if (DAD_InitDragImages())
  1961. g_pdiDragImages->InitializeFromWindow(hwnd, NULL, pdtobj);
  1962. }
  1963. HRESULT hr = DoDragDrop(pdtobj, pdsrc, dwEffect, pdwEffect);
  1964. if (pdsrcRelease)
  1965. pdsrcRelease->Release();
  1966. return hr;
  1967. }