dragdrop.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 74k
Category:

Windows Kernel

Development Platform:

Visual C++

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