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

Windows Kernel

Development Platform:

Visual C++

  1. #include "ctlspriv.h"
  2. #include "olestuff.h"
  3. //------------------------------------------------------------------------------
  4. STDAPI GetItemObject(CONTROLINFO *pci, UINT uMsg, const IID *piid, LPNMOBJECTNOTIFY pnon)
  5. {
  6.     pnon->piid = piid;
  7.     pnon->pObject = NULL;
  8.     pnon->hResult = E_NOINTERFACE;
  9.     CCSendNotify(pci, uMsg, &pnon->hdr);
  10.     ASSERT(SUCCEEDED(pnon->hResult) ? (pnon->pObject != NULL) : (pnon->pObject == NULL));
  11.     
  12.     return pnon->hResult;
  13. }
  14. //------------------------------------------------------------------------------
  15. class CDragProxy : public IDropTarget
  16. {
  17. public:
  18.     // IUnknown
  19.     STDMETHODIMP QueryInterface(REFIID, void **);
  20.     STDMETHODIMP_(ULONG) AddRef();
  21.     STDMETHODIMP_(ULONG) Release();
  22.     // IDropTarget
  23.     STDMETHODIMP DragEnter(IDataObject *, DWORD, POINTL, DWORD *);
  24.     STDMETHODIMP DragOver(DWORD, POINTL, DWORD *);
  25.     STDMETHODIMP DragLeave();
  26.     STDMETHODIMP Drop(IDataObject *, DWORD, POINTL, DWORD *);
  27.     CDragProxy(HWND hwnd, PFNDRAGCB pfn);
  28.     BOOL Register();
  29.     void RevokeAndFreeCB();
  30. private:
  31.     ~CDragProxy();
  32.     int          _cRef;             // object reference count
  33.     HWND         _hwnd;             // window that owns us
  34.     PFNDRAGCB    _pfnCallback;      // callback for that window
  35.     IDataObject *_pdtobj;           // data object being dragged
  36.     IDropTarget *_pdtgtItem;        // drop target of item under mouse
  37.     int          _idItem;           // id of item under mouse
  38.     DWORD        _dwFlags;
  39.     int          _idDefault;        // id to use when outside a drag etc
  40.     DWORD        _dwEffectItem;     // DROPEFFECT returned for item under mouse
  41.     DWORD        _fKeysLast;        // key flags from last DragOver
  42.     POINTL       _ptLast;           // location of last DragOver
  43.     DWORD        _dwEffectLast;     // effect available from last DragOver
  44.     HMODULE      _hmodOLE;          // OLE32 ref, also indicates we did a Register()
  45.     void SetTargetItem(int id, DWORD dwFlags);
  46.     void SetDropTarget(IDropTarget *pdt);
  47.     void UpdateSelection(DWORD dwEffect);
  48.     LRESULT CallCB(UINT code, WPARAM wp, LPARAM lp);
  49. };
  50. //------------------------------------------------------------------------------
  51. STDAPI_(HDRAGPROXY) CreateDragProxy(HWND hwnd, PFNDRAGCB pfn, BOOL bRegister)
  52. {
  53.     CDragProxy *pdp = new CDragProxy(hwnd, pfn);
  54.     //
  55.     // register as needed
  56.     //
  57.     if (pdp && bRegister && !pdp->Register())
  58.     {
  59.         pdp->Release();
  60.         pdp = NULL;
  61.     }
  62.     return (HDRAGPROXY)pdp;
  63. }
  64. STDAPI_(void) DestroyDragProxy(HDRAGPROXY hdp)
  65. {
  66.     if (hdp)
  67.     {
  68.         ((CDragProxy *)hdp)->RevokeAndFreeCB();
  69.         ((CDragProxy *)hdp)->Release();
  70.     }
  71. }
  72. STDAPI GetDragProxyTarget(HDRAGPROXY hdp, IDropTarget **ppdtgt)
  73. {
  74.     if (hdp)
  75.     {
  76.         *ppdtgt = SAFECAST((CDragProxy *)hdp, IDropTarget *);
  77.         ((CDragProxy *)hdp)->AddRef();
  78.         return NOERROR;
  79.     }
  80.     *ppdtgt = NULL;
  81.     return E_FAIL;
  82. }
  83. //------------------------------------------------------------------------------
  84. CDragProxy::CDragProxy(HWND hwnd, PFNDRAGCB pfn)
  85.     :   _hwnd(hwnd), _pfnCallback(pfn),
  86.         _cRef(1), 
  87.         _hmodOLE(NULL),
  88.         _pdtobj(NULL), 
  89.         _pdtgtItem(NULL),
  90.         _dwEffectItem(DROPEFFECT_NONE)
  91. {
  92.     _idDefault = _idItem = (int)CallCB(DPX_DRAGHIT, 0, 0);
  93. }
  94. CDragProxy::~CDragProxy()
  95. {
  96.     DragLeave();
  97. }
  98. HRESULT CDragProxy::QueryInterface(REFIID iid, void **ppv)
  99. {
  100.     if (IsEqualIID(iid, IID_IDropTarget) || IsEqualIID(iid, IID_IUnknown))
  101.     {
  102.         *ppv = SAFECAST(this, IDropTarget *);
  103.     }
  104.     else 
  105.     {
  106.         *ppv = NULL;
  107.         return E_NOINTERFACE;
  108.     }
  109.     _cRef++;
  110.     return NOERROR;
  111. }
  112. ULONG CDragProxy::AddRef()
  113. {
  114.     return ++_cRef;
  115. }
  116. ULONG CDragProxy::Release()
  117. {
  118.     if (--_cRef)
  119.         return _cRef;
  120.     delete this;
  121.     return 0;
  122. }
  123. HRESULT CDragProxy::DragEnter(IDataObject *pdo, DWORD fKeys, POINTL pt, DWORD *pdwEffect)
  124. {
  125.     //
  126.     // some sanity
  127.     //
  128.     ASSERT(!_pdtgtItem);
  129.     ASSERT(!_pdtobj);
  130.     if (!pdo)
  131.     {
  132.         ASSERT(FALSE);
  133.         return E_INVALIDARG;
  134.     }
  135.     //
  136.     // make sure our callback will allow us to do d/d now
  137.     //
  138.     if (!CallCB(DPX_ENTER, 0, 0))
  139.         return E_FAIL;
  140.     //
  141.     // save away the data object
  142.     //
  143.     pdo->AddRef();
  144.     _pdtobj = pdo;
  145.     //
  146.     // and process this like a DragOver
  147.     //
  148.     DragOver(fKeys, pt, pdwEffect);
  149.     //
  150.     // always succeed DragEnter
  151.     //
  152.     return NOERROR;
  153. }
  154. HRESULT CDragProxy::DragLeave()
  155. {
  156.     //
  157.     // release any drop target that we are holding
  158.     //
  159.     SetDropTarget(NULL);
  160.     _idItem = _idDefault;
  161.     //
  162.     // if we had a data object then we were actually dragging
  163.     //
  164.     if (_pdtobj)
  165.     {
  166.         CallCB(DPX_LEAVE, 0, 0);
  167.         IDataObject* p = _pdtobj;
  168.         _pdtobj = NULL;
  169.         p->Release();
  170.     }
  171.     //
  172.     // all done
  173.     //
  174.     return NOERROR;
  175. }
  176. HRESULT CDragProxy::DragOver(DWORD fKeys, POINTL pt, DWORD *pdwEffect)
  177. {
  178.     DWORD dwFlags = 0;
  179.     HRESULT hres;
  180.     int id;
  181.     ASSERT(_pdtobj);
  182.     //
  183.     // save the current drag state
  184.     //
  185.     _fKeysLast    = fKeys;
  186.     _ptLast       = pt;
  187.     _dwEffectLast = *pdwEffect;
  188.     //
  189.     // make sure we have the correct drop target for this location
  190.     //
  191.     id = (int)CallCB(DPX_DRAGHIT, (WPARAM)&dwFlags, (LPARAM)&pt);
  192.     SetTargetItem(id, dwFlags);
  193.     //
  194.     // do we have a target to drop on?
  195.     //
  196.     if (_pdtgtItem)
  197.     {
  198.         //
  199.         // forward the DragOver along to the item's drop target (if any)
  200.         //
  201.         hres = _pdtgtItem->DragOver(fKeys, pt, pdwEffect);
  202.     }
  203.     else
  204.     {
  205.         //
  206.         // can't drop here
  207.         //
  208.         *pdwEffect = DROPEFFECT_NONE;
  209.         hres = NOERROR;
  210.     }
  211.     //
  212.     // and update our selection state accordingly
  213.     //
  214.     UpdateSelection(*pdwEffect);
  215.     return hres;
  216. }
  217. HRESULT CDragProxy::Drop(IDataObject *pdo, DWORD fKeys, POINTL pt, DWORD *pdwEffect)
  218. {
  219.     HRESULT hres;
  220.     AddRef();
  221.     //
  222.     // do we have a target to drop on?
  223.     //
  224.     if (_pdtgtItem)
  225.     {
  226.         // From a comment in browseui, there's apparently a chance to put up UI
  227.         // which could cause us to get re-entered.  Hard to believe, but see if
  228.         // this fixes the fault:
  229.         //
  230.         IDropTarget * pdtCur = _pdtgtItem;
  231.         _pdtgtItem = NULL;
  232.         
  233.         //
  234.         // do the drop
  235.         //
  236.         hres = pdtCur->Drop(pdo, fKeys, pt, pdwEffect);
  237.         //
  238.         // we call our DragLeave below but we don't want the item's to be
  239.         // called (since it already saw the Drop) so we release right away
  240.         //
  241.         pdtCur->Release();
  242.     }
  243.     else
  244.     {
  245.         //
  246.         // can't drop here
  247.         //
  248.         *pdwEffect = DROPEFFECT_NONE;
  249.         hres = NOERROR;
  250.     }
  251.     //
  252.     // now clean up
  253.     //
  254.     DragLeave();
  255.     Release();
  256.     
  257.     return hres;
  258. }
  259. void CDragProxy::SetTargetItem(int id, DWORD dwFlags)
  260. {
  261.     //
  262.     // anything to do?
  263.     //
  264.     if (id == _idItem && dwFlags == _dwFlags)
  265.         return;
  266.     //
  267.     // deselect the old item (if any)
  268.     //
  269.     // the GETOBJECT below could take a long time and we don't want a
  270.     // lingering highlight on the object we are leaving
  271.     //
  272.     UpdateSelection(DROPEFFECT_NONE);
  273.     //
  274.     // get a drop target for the new item
  275.     //
  276.     _idItem = id;
  277.     _dwFlags = dwFlags;
  278.     NMOBJECTNOTIFY non;
  279.     non.iItem = id;
  280.     non.dwFlags = dwFlags;
  281.     if (!_pdtobj || FAILED((HRESULT)CallCB(DPX_GETOBJECT, 0, (LPARAM)&non)))
  282.         non.pObject = NULL;
  283.         //
  284.     // use this drop target (if any)
  285.     //
  286.     SetDropTarget((IDropTarget*)non.pObject);
  287.     //
  288.     // release our ref from the GETOBJECT above
  289.     //
  290.     if (non.pObject)
  291.         ((IDropTarget*)non.pObject)->Release();
  292. }
  293. void CDragProxy::SetDropTarget(IDropTarget *pdt)
  294. {
  295.     //
  296.     // NOTE: we intentionally skip the test for drop-target equality here
  297.     // this allows controls owners to share a target among multiple items
  298.     // while retaining the proper leave/enter sequence...
  299.     //
  300.     // BOGUS: we should actually compare here when the Internet Toolbar gets
  301.     //  fixed (see comment in CDragProxy::SetTargetItem).  anybody who wants
  302.     //  to share a target like this should just do the right hit-testing in
  303.     //  their DragOver implementation
  304.     //
  305.     //
  306.     // make sure nothing is selected
  307.     //
  308.     UpdateSelection(DROPEFFECT_NONE);
  309.     //
  310.     // leave/release the old item
  311.     //
  312.     if (_pdtgtItem)
  313.     {
  314.         _pdtgtItem->DragLeave();
  315.         _pdtgtItem->Release();
  316.     }
  317.     //
  318.     // store the new item
  319.     //
  320.     _pdtgtItem = pdt;
  321.     //
  322.     // addref/enter the new item
  323.     //
  324.     if (_pdtgtItem)
  325.     {
  326.         ASSERT(_pdtobj);    // must have a data object by now
  327.         _pdtgtItem->AddRef();
  328.         DWORD dwEffect = _dwEffectLast;
  329.         if (FAILED(_pdtgtItem->DragEnter(_pdtobj, _fKeysLast, _ptLast, &dwEffect)))
  330.             dwEffect = DROPEFFECT_NONE;
  331.         //
  332.         // update the selection
  333.         //
  334.         UpdateSelection(dwEffect);
  335.     }
  336. }
  337. void CDragProxy::UpdateSelection(DWORD dwEffect)
  338. {
  339.     //
  340.     // anything to do?
  341.     //
  342.     if (dwEffect == _dwEffectItem)
  343.         return;
  344.     //
  345.     // update the flags and tell the callback they changed
  346.     //
  347.     _dwEffectItem = dwEffect;
  348.     CallCB(DPX_SELECT, (WPARAM)_idItem, (LPARAM)dwEffect);
  349. }
  350. LRESULT CDragProxy::CallCB(UINT code, WPARAM wp, LPARAM lp)
  351. {
  352.     return _pfnCallback ? _pfnCallback(_hwnd, code, wp, lp) : (LRESULT)-1;
  353. }
  354. BOOL CDragProxy::Register()
  355. {
  356.     _hmodOLE = PrivLoadOleLibrary();
  357.     if (_hmodOLE)
  358.     {
  359.         if (SUCCEEDED(PrivCoInitialize(_hmodOLE)))
  360.         {
  361.             if (SUCCEEDED(PrivRegisterDragDrop(_hmodOLE, _hwnd, this)))
  362.                 return TRUE;
  363.             PrivCoUninitialize(_hmodOLE);
  364.         }
  365.         PrivFreeOleLibrary(_hmodOLE);
  366.         _hmodOLE = NULL;
  367.     }
  368.     return FALSE;
  369. }
  370. void CDragProxy::RevokeAndFreeCB()
  371. {
  372.     if (_hmodOLE)
  373.     {
  374.         PrivRevokeDragDrop(_hmodOLE, _hwnd);
  375.         PrivCoUninitialize(_hmodOLE);
  376.         PrivFreeOleLibrary(_hmodOLE);
  377.     }
  378.     _pfnCallback = NULL;
  379. }