nscdrop.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 9k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include <windows.h>
  2. #include <commctrl.h>
  3. #include <shlobj.h>
  4. #include "debug.h"
  5. #include "common.h"
  6. #include "autoscrl.h"
  7. #include "nsc.h"
  8. // BUGBUG: do nothing for now
  9. #define DAD_DragLeave()
  10. #define DAD_DragEnterEx(hwndLock, pt)
  11. #define DAD_ShowDragImage(f)
  12. #define DAD_DragMove(pt)
  13. typedef struct { // tdt
  14.     IDropTarget dtgt;
  15.     UINT cRef;
  16.     NSC *pns;
  17.     RECT _rcLockWindow;
  18.     HTREEITEM _htiCur; // current tree item (dragging over)
  19.     IDropTarget *_pdtgtCur; // current drop target
  20.     IDataObject *_pdtobjCur; // current data object
  21.     DWORD _dwEffectCur; // current drag effect
  22.     DWORD _dwEffectIn; // *pdwEffect passed-in on last Move/Enter
  23.     DWORD               _grfKeyState;   // cached key state
  24.     POINT _ptLast; // last dragged over position
  25.     DWORD               _dwLastTime;
  26.     AUTO_SCROLL_DATA asd;
  27. } CTreeDropTarget;
  28. STDMETHODIMP CTreeDropTarget_QueryInterface(IDropTarget *pdtgt, REFIID riid, void **ppvObj)
  29. {
  30.     CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  31.     if (IsEqualIID(riid, &IID_IDropTarget) || IsEqualIID(riid, &IID_IUnknown))
  32.     {
  33.         *ppvObj = pdtgt;
  34.         this->cRef++;
  35.         return S_OK;
  36.     }
  37.     *ppvObj = NULL;
  38.     return E_NOINTERFACE;
  39. }
  40. STDMETHODIMP_(ULONG) CTreeDropTarget_AddRef(IDropTarget *pdtgt)
  41. {
  42.     CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  43.     this->cRef++;
  44.     return this->cRef;
  45. }
  46. void CTreeDropTarget_ReleaseDataObject(CTreeDropTarget *this)
  47. {
  48.     if (this->_pdtobjCur)
  49. Release(this->_pdtobjCur);
  50.     this->_pdtobjCur = NULL;
  51. }
  52. void CTreeDropTarget_ReleaseCurrentDropTarget(CTreeDropTarget *this)
  53. {
  54.     if (this->_pdtgtCur)
  55.     {
  56. this->_pdtgtCur->lpVtbl->DragLeave(this->_pdtgtCur);
  57. Release(this->_pdtgtCur);
  58.         this->_pdtgtCur = NULL;
  59.         this->_htiCur = NULL;
  60.     }
  61.     else
  62.     {
  63. Assert(this->_htiCur == NULL);
  64.     }
  65. }
  66. STDMETHODIMP_(ULONG) CTreeDropTarget_Release(IDropTarget * pdtgt)
  67. {
  68.     CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  69.     this->cRef--;
  70.     if (this->cRef > 0)
  71.         return this->cRef;
  72.     AssertMsg(this->_pdtgtCur == NULL, "drag leave was not called properly");
  73.     // if above is true we can remove this...
  74.     CTreeDropTarget_ReleaseCurrentDropTarget(this);
  75.     LocalFree(this);
  76.     return 0;
  77. }
  78. STDMETHODIMP CTreeDropTarget_DragEnter(IDropTarget *pdtgt, IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  79. {
  80.     CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  81.     POINT pt;
  82.     HWND hwndLock;
  83.     DebugMsg(DM_TRACE, "sh - TR CTreeDropTarget::DragEnter called");
  84.     CTreeDropTarget_ReleaseDataObject(this);
  85.     this->_pdtobjCur = pdtobj;
  86.     this->_grfKeyState = grfKeyState;
  87.     AddRef(pdtobj);
  88.     Assert(this->_pdtgtCur == NULL);
  89.     Assert(this->_htiCur == NULL);
  90.     hwndLock = this->pns->hwndTree;     // clip to this
  91.     GetWindowRect(hwndLock, &this->_rcLockWindow);
  92.     pt.x = ptl.x-this->_rcLockWindow.left;
  93.     pt.y = ptl.y-this->_rcLockWindow.top;
  94.     DAD_DragEnterEx(hwndLock, pt);
  95.     this->_ptLast.x = this->_ptLast.y = 0x7ffffff; // set bogus position
  96.     return S_OK;
  97. }
  98. STDMETHODIMP CTreeDropTarget_DragOver(IDropTarget *pdtgt, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  99. {
  100.     HRESULT hres = S_OK;
  101.     CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  102.     TV_HITTESTINFO tvht;
  103.     HTREEITEM htiNew;
  104.     POINT pt = { ptl.x, ptl.y };
  105.     BOOL fSameImage = FALSE;
  106.     DWORD dwEffectScroll = 0;
  107.     ScreenToClient(this->pns->hwndTree, &pt);
  108.     if (DAD_AutoScroll(this->pns->hwndTree, &this->asd, &pt))
  109.         dwEffectScroll = DROPEFFECT_SCROLL;
  110.     tvht.pt = pt;
  111.     htiNew = TreeView_HitTest(this->pns->hwndTree, &tvht);
  112.     // don't allow droping on the item being dragged
  113.     if (htiNew == this->pns->htiDragging)
  114.         htiNew = NULL;
  115.     if (this->_htiCur != htiNew)
  116.     {
  117.         // change in target
  118.         this->_dwLastTime = GetTickCount();     // keep track for auto-expanding the tree
  119. CTreeDropTarget_ReleaseCurrentDropTarget(this);
  120. this->_dwEffectCur = 0; // assume error
  121. DAD_ShowDragImage(FALSE);
  122. TreeView_SelectDropTarget(this->pns->hwndTree, htiNew);
  123. DAD_ShowDragImage(TRUE);
  124. if (htiNew)
  125. {
  126.             // get the drop target for the item we hit
  127.     LPITEMIDLIST pidl = _CacheParentShellFolder(this->pns, htiNew, NULL);
  128.     if (pidl)
  129.     {
  130.         IShellFolder *psf = this->pns->psfCache;
  131. AddRef(psf);
  132.         if (pidl->mkid.cb == 0)
  133. {
  134.     hres = psf->lpVtbl->CreateViewObject(psf, this->pns->hwnd, &IID_IDropTarget, &this->_pdtgtCur);
  135. }
  136. else
  137. {
  138.     UINT dwAttr = SFGAO_DROPTARGET;
  139.     hres = psf->lpVtbl->GetAttributesOf(psf, 1, &pidl, &dwAttr);
  140.     if (SUCCEEDED(hres) && (dwAttr & SFGAO_DROPTARGET))
  141.     {
  142. hres = psf->lpVtbl->GetUIObjectOf(psf, this->pns->hwnd, 1, &pidl, &IID_IDropTarget, NULL, &this->_pdtgtCur);
  143.     }
  144.     else
  145.     {
  146. hres = E_INVALIDARG;
  147.     }
  148. }
  149. Release(psf);
  150.     }
  151.     if (SUCCEEDED(hres))
  152.     {
  153. this->_htiCur = htiNew;
  154. this->_dwEffectCur = *pdwEffect; // pdwEffect is In/Out
  155. hres = this->_pdtgtCur->lpVtbl->DragEnter(this->_pdtgtCur, this->_pdtobjCur, grfKeyState, ptl, &this->_dwEffectCur);
  156.     }
  157.     }
  158.     else
  159.     {
  160.         // No target change
  161.         // auto expand the tree
  162.         if (this->_htiCur)
  163.         {
  164.             DWORD dwNow = GetTickCount();
  165.             if ((dwNow - this->_dwLastTime) >= 1000)
  166.             {
  167.                 this->_dwLastTime = dwNow;
  168.                 DAD_ShowDragImage(FALSE);
  169.                 this->pns->fAutoExpanding = TRUE;
  170.                 TreeView_Expand(this->pns->hwndTree, this->_htiCur, TVE_EXPAND);
  171.                 this->pns->fAutoExpanding = FALSE;
  172.                 DAD_ShowDragImage(TRUE);
  173.             }
  174.         }
  175. // maybe the key state changed
  176.         if ((this->_grfKeyState != grfKeyState) && this->_pdtgtCur) 
  177. {
  178.             this->_dwEffectCur = *pdwEffect;
  179.             hres = this->_pdtgtCur->lpVtbl->DragOver(this->_pdtgtCur, grfKeyState, ptl, &this->_dwEffectCur);
  180.         } 
  181. else 
  182. {
  183.     fSameImage = TRUE;
  184.             hres = S_OK;
  185.         }
  186.     }
  187.     DebugMsg(DM_TRACE, "sh TR - CTreeDropTarget_DragOver (In=%x, Out=%x)", *pdwEffect, this->_dwEffectCur);
  188.     this->_grfKeyState = grfKeyState;
  189.     *pdwEffect = this->_dwEffectCur | dwEffectScroll;
  190.     // We need pass pt relative to the locked window (not the client).
  191.     pt.x = ptl.x-this->_rcLockWindow.left;
  192.     pt.y = ptl.y-this->_rcLockWindow.top;
  193.     if (!(fSameImage && this->_ptLast.x == pt.x && this->_ptLast.y == pt.y))
  194.     {
  195. DAD_DragMove(pt);
  196. this->_ptLast.x = pt.x;
  197. this->_ptLast.y = pt.y;
  198.     }
  199.     return hres;
  200. }
  201. STDMETHODIMP CTreeDropTarget_DragLeave(IDropTarget *pdtgt)
  202. {
  203.     CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  204.     DebugMsg(DM_TRACE, "sh - TR CTreeDropTarget::DragLeave called");
  205.     CTreeDropTarget_ReleaseCurrentDropTarget(this);
  206.     CTreeDropTarget_ReleaseDataObject(this);
  207.     DAD_DragLeave();
  208.     TreeView_SelectDropTarget(this->pns->hwndTree, NULL);
  209.     return S_OK;
  210. }
  211. STDMETHODIMP CTreeDropTarget_Drop(IDropTarget *pdtgt, IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  212. {
  213.     HRESULT hres;
  214.     CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  215.     if (this->_pdtgtCur)
  216.     {
  217. hres = this->_pdtgtCur->lpVtbl->Drop(this->_pdtgtCur, pdtobj, grfKeyState, pt, pdwEffect);
  218.     }
  219.     else
  220.     {
  221. DebugMsg(DM_TRACE, "sh TR - CTreeDropTarget::Drop - this->_pdtgtCur==NULL");
  222. *pdwEffect = 0;
  223. hres = S_OK;
  224.     }
  225.     CTreeDropTarget_DragLeave(pdtgt);
  226.     return hres;
  227. }
  228. const IDropTargetVtbl c_CTreeDropTargetVtbl = {
  229.     CTreeDropTarget_QueryInterface, CTreeDropTarget_AddRef, CTreeDropTarget_Release,
  230.     CTreeDropTarget_DragEnter,
  231.     CTreeDropTarget_DragOver,
  232.     CTreeDropTarget_DragLeave,
  233.     CTreeDropTarget_Drop
  234. };
  235. HRESULT CTreeDropTarget_Create(NSC *pns, IDropTarget **ppdtgt)
  236. {
  237.     CTreeDropTarget * this = LocalAlloc(LPTR, sizeof(CTreeDropTarget));
  238.     if (this)
  239.     {
  240. this->dtgt.lpVtbl = (IDropTargetVtbl *)&c_CTreeDropTargetVtbl;
  241. this->cRef = 1;
  242. this->pns = pns;
  243. *ppdtgt = &this->dtgt;
  244. return S_OK;
  245.     }
  246.     *ppdtgt = NULL;
  247.     return E_OUTOFMEMORY;
  248. }
  249. void CTreeDropTarget_Register(NSC *pns)
  250. {
  251.     IDropTarget *pdtgt;
  252.     if (SUCCEEDED(CTreeDropTarget_Create(pns, &pdtgt)))
  253.     {
  254. RegisterDragDrop(pns->hwndTree, pdtgt);
  255.         Release(pdtgt);
  256.     }
  257. }
  258. void CTreeDropTarget_Revoke(NSC *pns)
  259. {
  260.     RevokeDragDrop(pns->hwndTree);
  261. }