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

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include "droptgt.h"
  3. #define TF_DRAGDROP TF_BAND
  4. #define MAX_DROPTARGETS 3
  5. class CDropTargetWrap : public IDropTarget
  6. {
  7. public:
  8.     // *** IUnknown ***
  9.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  10.     virtual STDMETHODIMP_(ULONG) Release(void);
  11.     virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  12.     // *** IDropTarget methods ***
  13.     virtual STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  14.     virtual STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  15.     virtual STDMETHODIMP DragLeave(void);
  16.     virtual STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  17.     CDropTargetWrap(IDropTarget** ppdtg, HWND hwnd);
  18. protected:
  19.     ~CDropTargetWrap();
  20. private:
  21.     int             _cRef;
  22.     int             _count;
  23.     IDropTarget*    _rgpdt[MAX_DROPTARGETS];
  24.     DWORD           _rgdwEffect[MAX_DROPTARGETS];
  25.     HWND            _hwnd;
  26. };
  27. CDropTargetWrap::CDropTargetWrap(IDropTarget** ppdt, HWND hwnd)
  28.     : _hwnd(hwnd)
  29. {
  30.     _cRef = 1;
  31.     for (int i = 0; i < MAX_DROPTARGETS; i++, ppdt++) {
  32.         if (*ppdt) {
  33.             _rgpdt[_count] = *ppdt;
  34.             _rgpdt[_count]->AddRef();
  35.             _count++;
  36.         }
  37.     }
  38. }
  39. CDropTargetWrap::~CDropTargetWrap()
  40. {
  41.     for (int i = 0 ; i < _count ; i++)
  42.     {
  43.         _rgpdt[i]->Release();
  44.     }
  45. }
  46. HRESULT CDropTargetWrap::QueryInterface(REFIID riid, void **ppvObj)
  47. {
  48.     static const QITAB qit[] = {
  49.         QITABENT(CDropTargetWrap, IDropTarget),
  50.         { 0 },
  51.     };
  52.     return QISearch(this, qit, riid, ppvObj);
  53. }
  54. ULONG CDropTargetWrap::AddRef(void)
  55. {
  56.     _cRef++;
  57.     return _cRef;
  58. }
  59. ULONG CDropTargetWrap::Release(void)
  60. {
  61.     _cRef--;
  62.     if (_cRef > 0)
  63.         return _cRef;
  64.     delete this;
  65.     return 0;
  66. }
  67. /*----------------------------------------------------------
  68. Purpose: IDropTarget::DragEnter method
  69.          The *pdwEffect that is returned is the first valid value
  70.          of all the drop targets' returned effects.
  71. */
  72. HRESULT CDropTargetWrap::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  73. {
  74.     DWORD dwEffectOut = DROPEFFECT_NONE;
  75.     for (int i = 0 ; i < _count ; i++)
  76.     {
  77.         _rgdwEffect[i] = *pdwEffect;
  78.         if (SUCCEEDED(_rgpdt[i]->DragEnter(pdtobj, grfKeyState, ptl, &_rgdwEffect[i])))
  79.         {
  80.             if (dwEffectOut == DROPEFFECT_NONE)
  81.             {
  82.                 dwEffectOut = _rgdwEffect[i];
  83.             }
  84.         }
  85.         else
  86.         {
  87.             _rgdwEffect[i] = DROPEFFECT_NONE;
  88.         }
  89.     }
  90.     *pdwEffect = dwEffectOut;
  91.     return(S_OK);
  92. }
  93. /*----------------------------------------------------------
  94. Purpose: IDropTarget::DragOver method
  95. */
  96. HRESULT CDropTargetWrap::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  97. {
  98.     DWORD dwEffectOut = DROPEFFECT_NONE;
  99.         
  100.     for (int i = 0 ; i < _count ; i++)
  101.     {
  102.         _rgdwEffect[i] = *pdwEffect;
  103.         if (SUCCEEDED(_rgpdt[i]->DragOver(grfKeyState, ptl, &_rgdwEffect[i])))
  104.         {
  105.             if (dwEffectOut == DROPEFFECT_NONE)
  106.                 dwEffectOut = _rgdwEffect[i];
  107.         }
  108.         else
  109.         {
  110.             _rgdwEffect[i] = DROPEFFECT_NONE;
  111.         }
  112.     }
  113.     *pdwEffect = dwEffectOut;
  114.     return(S_OK);
  115. }
  116. /*----------------------------------------------------------
  117. Purpose: IDropTarget::DragLeave method
  118. */
  119. HRESULT CDropTargetWrap::DragLeave(void)
  120. {
  121.     for (int i = 0 ; i < _count ; i++)
  122.     {
  123.         _rgpdt[i]->DragLeave();
  124.     }
  125.     return(S_OK);
  126. }
  127. /*----------------------------------------------------------
  128. Purpose: IDropTarget::Drop method
  129. */
  130. HRESULT CDropTargetWrap::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  131. {
  132.     DWORD dwEffectOut = DROPEFFECT_NONE;
  133.     int i;
  134.     BOOL fDropTried = FALSE;
  135.     for (i = 0 ; (DROPEFFECT_NONE == dwEffectOut) && i < _count ; i++)
  136.     {
  137.         if ((_rgdwEffect[i] && *pdwEffect) && !fDropTried)
  138.         {
  139.             dwEffectOut = *pdwEffect;
  140.             _rgpdt[i]->Drop(pdtobj, grfKeyState, pt, &dwEffectOut);
  141.             fDropTried = TRUE;
  142.         }
  143.         else
  144.         {
  145.             _rgpdt[i]->DragLeave();
  146.         }
  147.     }
  148.     *pdwEffect = dwEffectOut;
  149.     return(S_OK);
  150. }
  151. //=============================================================================
  152. // CDelegateDropTarget
  153. //
  154. // This class implements IDropTarget given an IDelegateDropTargetCB interface.
  155. // It handles all hit testing, caching, and scrolling for you.
  156. //
  157. //=============================================================================
  158. #undef  CDropTargetWrap
  159. CDelegateDropTarget::CDelegateDropTarget()
  160. {
  161.     TraceMsg(TF_SHDLIFE, "ctor CDelegateDropTarget %x", this);
  162. }
  163. CDelegateDropTarget::~CDelegateDropTarget()
  164. {
  165.     TraceMsg(TF_SHDLIFE, "dtor CDelegateDropTarget %x", this);
  166.     ASSERT(!_pDataObj);
  167.     ATOMICRELEASE(_pDataObj);
  168.     ASSERT(!_pdtCur);
  169.     ATOMICRELEASE(_pdtCur);
  170. }
  171. HRESULT CDelegateDropTarget::Init()
  172. {
  173.     HRESULT hres = GetWindowsDDT(&_hwndLock, &_hwndScroll);
  174.     // We lock _hwndLock and do scrolling against _hwndScroll.
  175.     // These can be different hwnds, but certain restrictions apply:
  176.     if (_hwndLock != _hwndScroll)
  177.     {
  178.         BOOL fValid = IsChild(_hwndLock, _hwndScroll);
  179.         if (!fValid)
  180.         {
  181.             TraceMsg(TF_DRAGDROP, "ctor CDelegateDropTarget: invalid windows %x and %x!", _hwndLock, _hwndScroll);
  182.             _hwndLock = _hwndScroll = NULL;
  183.         }
  184.     }
  185.     return hres;
  186. }
  187. void CDelegateDropTarget::_ReleaseCurrentDropTarget()
  188. {
  189.     if (_pdtCur)
  190.     {
  191.         _pdtCur->DragLeave();
  192.         ATOMICRELEASE(_pdtCur);
  193.     }
  194. }
  195. /*----------------------------------------------------------
  196. Purpose: IDropTarget::DragEnter method
  197. */
  198. HRESULT CDelegateDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, LPDWORD pdwEffect)
  199. {
  200.     // We can be re-entered due to ui on thread
  201.     if (_pDataObj != NULL)       
  202.     {
  203.         TraceMsg(TF_DRAGDROP, "CDelegateDropTarget::DragEnter called a second time!");
  204.         *pdwEffect = DROPEFFECT_NONE;
  205.         return S_OK;
  206.     }
  207.     TraceMsg(TF_DRAGDROP, "CDelegateDropTarget::DragEnter with *pdwEffect=%x", *pdwEffect);
  208.     ASSERT(!_pDataObj);
  209.     _pDataObj = pdtobj;
  210.     _pDataObj->AddRef();
  211.     // cache state
  212.     //
  213.     // wait until first DragOver to get valid info
  214.     //
  215.     _fPrime = FALSE;
  216.     _dwEffectOut = DROPEFFECT_NONE;
  217.     // set up auto-scroll info
  218.     //
  219.     ASSERT(pdtobj);
  220.     _DragEnter(_hwndLock, ptl, pdtobj);
  221.     DAD_InitScrollData(&_asd);
  222.     _ptLast.x = _ptLast.y = 0x7fffffff; // put bogus value to force redraw
  223.     HitTestDDT(HTDDT_ENTER, NULL, NULL, NULL);
  224.     return S_OK;
  225. }
  226. /*----------------------------------------------------------
  227. Purpose: IDropTarget::DragOver method
  228. */
  229. HRESULT CDelegateDropTarget::DragOver(DWORD grfKeyState, POINTL ptl, LPDWORD pdwEffect)
  230. {
  231.     HRESULT hres = S_OK;
  232.     DWORD itemNew;
  233.     POINT pt;
  234.     DWORD dwEffectScroll = 0;
  235.     DWORD dwEffectOut = 0;
  236.     BOOL fSameImage = FALSE;
  237.     DWORD   dwCustDropEffect = 0;
  238.     if (_pDataObj == NULL)
  239.     {
  240.         ASSERT(0);      // DragEnter should be called before.
  241.         return E_FAIL;
  242.     }
  243.     // convert to window coords
  244.     pt.x = ptl.x;
  245.     pt.y = ptl.y;
  246.     ScreenToClient(_hwndScroll, &pt);
  247.     if (DAD_AutoScroll(_hwndScroll, &_asd, &pt))
  248.         dwEffectScroll = DROPEFFECT_SCROLL;
  249.     //
  250.     //  If we are dragging over on a different item, get its IDropTarget
  251.     // interface or adjust itemNew to -1.
  252.     //
  253.     if (SUCCEEDED(HitTestDDT(HTDDT_OVER, &pt, &itemNew, &dwCustDropEffect)) &&
  254.         (itemNew != _itemOver || !_fPrime))
  255.     {
  256.         _fPrime = TRUE;
  257.         _ReleaseCurrentDropTarget();
  258.         _itemOver = itemNew;
  259.         GetObjectDDT(_itemOver, IID_IDropTarget, (LPVOID*)&_pdtCur);
  260.         if (_pdtCur)
  261.         {
  262.             // There's an IDropTarget for this hit, use it
  263.             dwEffectOut = *pdwEffect;
  264.             hres = _pdtCur->DragEnter(_pDataObj, grfKeyState, ptl, &dwEffectOut);
  265.             if (FAILED(hres))
  266.                 dwEffectOut = DROPEFFECT_NONE;
  267.         }
  268.         else
  269.         {
  270.             // No IDropTarget, no effect
  271.             dwEffectOut = DROPEFFECT_NONE;
  272.         }
  273.     }
  274.     else
  275.     {
  276.         //
  277.         // No change in the selection. We assume that *pdwEffect stays
  278.         // the same during the same drag-loop as long as the key state doesn't change.
  279.         //
  280.         if ((_grfKeyState != grfKeyState) && _pdtCur)
  281.         {
  282.             dwEffectOut = *pdwEffect;
  283.             hres = _pdtCur->DragOver(grfKeyState, ptl, &dwEffectOut);
  284.             TraceMsg(TF_DRAGDROP, "CDelegateDropTarget::DragOver DragOver()d id:%d dwEffect:%4x hres:%d", _itemOver, dwEffectOut, hres);
  285.         }
  286.         else
  287.         {
  288.             // Same item and same key state. Use the previous dwEffectOut.
  289.             dwEffectOut = _dwEffectOut;
  290.             fSameImage = TRUE;
  291.         }
  292.     }
  293.     _grfKeyState = grfKeyState;    // store these for the next Drop
  294.     _dwEffectOut = dwEffectOut;    // and DragOver
  295.     // Is the Custdrop effect valid ?
  296.     if (dwCustDropEffect != DROPEFFECT_NONE)    
  297.     {
  298.         //Yes then set the effect to Custdrop effect along with scroll effect
  299.         *pdwEffect = dwCustDropEffect | dwEffectScroll;
  300.     }
  301.     else 
  302.     {
  303.         //No , set the effect to dwEffectOut along with scroll effect
  304.         *pdwEffect = dwEffectOut | dwEffectScroll;
  305.     }
  306.         TraceMsg(TF_DRAGDROP, "CDelegateDropTarget::DragOver (*pdwEffect=%x)", *pdwEffect);
  307.     if (!(fSameImage && pt.x==_ptLast.x && pt.y==_ptLast.y))
  308.     {
  309.         _DragMove(_hwndLock, ptl);
  310.         _ptLast.x = ptl.x;
  311.         _ptLast.y = ptl.y;
  312.     }
  313.     return hres;
  314. }
  315. /*----------------------------------------------------------
  316. Purpose: IDropTarget::DragLeave method
  317. */
  318. HRESULT CDelegateDropTarget::DragLeave()
  319. {
  320.     HitTestDDT(HTDDT_LEAVE, NULL, NULL, NULL);
  321.     _ReleaseCurrentDropTarget();
  322.     TraceMsg(TF_DRAGDROP, "CDelegateDropTarget::DragLeave");
  323.     ATOMICRELEASE(_pDataObj);
  324.     DAD_DragLeave();
  325.     return S_OK;
  326. }
  327. /*----------------------------------------------------------
  328. Purpose: IDropTarget::Drop method
  329. */
  330. HRESULT CDelegateDropTarget::Drop(IDataObject *pdtobj,
  331.                              DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
  332. {
  333.     HRESULT hres = S_OK;
  334.     BOOL bDropHandled = FALSE;
  335.     TraceMsg(TF_DRAGDROP, "CDelegateDropTarget::Drop (*pdwEffect=%x)", *pdwEffect);
  336.     //
  337.     // According to AlexGo (OLE), this is by-design. We should make it sure
  338.     // that we use pdtobj instead of pdtobj.
  339.     //
  340.     //ASSERT(pdtobj == _pDataObj);
  341.     pdtobj->AddRef();
  342.     _pDataObj->Release();
  343.     _pDataObj = pdtobj;
  344.     //
  345.     // Note that we don't use the drop position intentionally,
  346.     // so that it matches to the last destination feedback.
  347.     //
  348.     if (_pdtCur)
  349.     {
  350.         // use this local because if _pdtCur::Drop does a UnlockWindow
  351.         // then hits an error and needs to put up a dialog,
  352.         // we could get re-entered
  353.         IDropTarget *pdtCur = _pdtCur;
  354.         _pdtCur = NULL;
  355.         // HACK ALERT!!!!
  356.         //
  357.         //  If we don't call LVUtil_DragEnd here, we'll be able to leave
  358.         // dragged icons visible when the menu is displayed. However, because
  359.         // we are calling IDropTarget::Drop() which may create some modeless
  360.         // dialog box or something, we can not ensure the locked state of
  361.         // the list view -- LockWindowUpdate() can lock only one window at
  362.         // a time. Therefore, we skip this call only if the _pdtCur
  363.         // is a subclass of CIDLDropTarget, assuming its Drop calls
  364.         // CDefView::DragEnd (or CIDLDropTarget_DragDropMenu) appropriately.
  365.         //
  366. #if 0 // later
  367.         if (!IsIDLDropTarget(pdtCur))
  368. #endif
  369.         {
  370.             //
  371.             // This will hide the dragged image.
  372.             //
  373.             DAD_DragLeave();
  374.             //
  375.             //  We need to reset the drag image list so that the user
  376.             // can start another drag&drop while we are in this
  377.             // Drop() member function call.
  378.             //
  379.             // NOTE: we don't have to worry about the DAD_DragLeave
  380.             // (called from during the DragLeave call at the end of
  381.             // this function) cancelling the potential above-mentioned
  382.             // drag&drop loop. If such a beast is going on, it should
  383.             // complete before pdtCur->Drop returns.
  384.             //
  385.             DAD_SetDragImage(NULL, NULL);
  386.         }
  387.         if (S_FALSE != OnDropDDT(pdtCur, _pDataObj, &grfKeyState, pt, pdwEffect))
  388.             pdtCur->Drop(_pDataObj, grfKeyState, pt, pdwEffect);
  389.         else
  390.             pdtCur->DragLeave(); // should be okay even if OnDrop did this already
  391.         pdtCur->Release();
  392.     }
  393.     else
  394.     {
  395.         //
  396.         // We come here if Drop is called without DragMove (with DragEnter).
  397.         //
  398.         *pdwEffect = DROPEFFECT_NONE;
  399.     }
  400.     //
  401.     // Clean up everything (OLE won't call DragLeave after Drop).
  402.     //
  403.     DragLeave();
  404.     return hres;
  405. }
  406. // ******************************************************************
  407. // dummy drop target to only call DAD_DragEnterEx() on DragEnter();
  408. // ******************************************************************
  409. HRESULT CDropDummy::QueryInterface(REFIID riid, void **ppvObj)
  410. {
  411.     static const QITAB qit[] = {
  412.         QITABENT(CDropDummy, IDropTarget),
  413.         { 0 },
  414.     };
  415.     return QISearch(this, qit, riid, ppvObj);
  416. }
  417. ULONG CDropDummy::AddRef(void)
  418. {
  419.     _cRef++;
  420.     return _cRef;
  421. }
  422. ULONG CDropDummy::Release(void)
  423. {
  424.     _cRef--;
  425.     if (_cRef > 0)
  426.         return _cRef;
  427.     delete this;
  428.     return 0;
  429. }
  430. /*----------------------------------------------------------
  431. Purpose: IDropTarget::DragEnter method
  432.          simply call DAD_DragEnterEx2() to get custom drag cursor 
  433.          drawing.
  434. */
  435. HRESULT CDropDummy::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  436. {
  437.     ASSERT(pdtobj);
  438.     _DragEnter(_hwndLock, ptl, pdtobj);
  439.     *pdwEffect = DROPEFFECT_NONE;
  440.     return(S_OK);
  441. }
  442. HRESULT CDropDummy::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  443. {
  444.     _DragMove(_hwndLock, ptl);
  445.     *pdwEffect = DROPEFFECT_NONE;
  446.     return  S_OK;
  447. }