SOL9 2.0 Class: DropTarget

 SOL9 C++ Class Library  SOL9 Samples  SOL9 Tutorial  SOL9 FAQ  SOL9 ClassTree  SOL9 ClassList 

Source code

/******************************************************************************
 *
 * Copyright (c) 2008 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *  DropTarget.h
 *
 *****************************************************************************/

// SOL9 2008/12/11

#pragma once

#include <sol\Object.h>


//SOL9 specific user-defined message,which can be sent
// to the window of m_hReceiver, this will be a window
// of user's application.
// If m_hReciever is NULL, this message will be sent the drop target 
// of m_hTarget window.

#define WM_SOL_DROPFILES  (WM_USER+2011)

namespace SOL {

/**
 * class DropTarget.
 * Implementation of the IDropTarget interface
 */
class CDropTarget :public IDropTarget {

// Member variables
private:
  LONG  m_lRefCount;
  HWND  m_hTarget;
  HWND  m_hReceiver;
  bool    m_fAllowDrop;
  IDataObject *m_pDataObject;


public:
  // IUnknown implementation
  HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject)
  {
    if(iid == IID_IDropTarget || iid == IID_IUnknown) {
      AddRef();
      *ppvObject = this;
  
      return S_OK;

    } else {
      *ppvObject = 0;
      return E_NOINTERFACE;
    }
  }

public:
  ULONG  __stdcall AddRef (void) 
  {
    return InterlockedIncrement(&m_lRefCount);
  }

public:
  ULONG  __stdcall Release (void) 
  {
    LONG count = InterlockedDecrement(&m_lRefCount);
    
    if(count == 0) {
      delete this;
      return 0;
    } else {
      return count;
    }
  }

public:
  // IDropTarget implementation
  HRESULT __stdcall DragEnter (IDataObject * pDataObject, DWORD grfKeyState, 
    POINTL pt, DWORD * pdwEffect)
  {
    // Check the dataobject
    m_fAllowDrop = QueryDataObject(pDataObject);
  
    if(m_fAllowDrop) {
      // Get the dropeffect based on keyboard state
      *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);

      SetFocus(m_hTarget);

    } else {
      *pdwEffect = DROPEFFECT_NONE;
    }

    return S_OK;
  }


public:
  HRESULT __stdcall DragOver (DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
  {
    if(m_fAllowDrop) {
      *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);

    } else {
      *pdwEffect = DROPEFFECT_NONE;
    }

    return S_OK;
  }

public:
  HRESULT __stdcall DragLeave (void)
  {
    m_fAllowDrop = false;

    return S_OK;
  }

public:
  HRESULT __stdcall Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
  {

    if(m_fAllowDrop) {
      DropData(m_hTarget, pDataObject);

      *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);

    } else {
      *pdwEffect = DROPEFFECT_NONE;
    }
    return S_OK;
  }

//
// 
//
public:
  // Constructor
  CDropTarget(HWND hwnd) 
  {
    m_lRefCount  = 1;
    m_hTarget       = hwnd;
    m_hReceiver  = NULL;

    m_fAllowDrop = false;
    m_pDataObject = NULL;
  }

public:
  // Constructor
  CDropTarget() 
  {
    m_lRefCount  = 1;
    m_hTarget       = NULL;
    m_hReceiver  = NULL;
    m_fAllowDrop = false;
    m_pDataObject = NULL;
  }

public:
  //Destructor
  ~CDropTarget() 
  {
    //2009/11/01
    if (m_hTarget && IsWindow(m_hTarget)) {
      RevokeDragDrop(m_hTarget);
    
      // Remove the strong lock
      CoLockObjectExternal(this, FALSE, TRUE);
      Release();
    }
    // release our own reference
    m_hTarget = NULL;
  }

public:
  void setTarget(HWND hwnd) {
    if (hwnd) {
      DragAcceptFiles(hwnd, TRUE);
      m_hTarget = hwnd;
      RegisterDragDrop(hwnd, this);
      CoLockObjectExternal(this, TRUE, FALSE);
    }
  }
public:
  void setEventReceiver(HWND hwnd) {
    //2009/11/01
    if (hwnd) {
      DragAcceptFiles(hwnd, TRUE);
    }
    m_hReceiver = hwnd;
  }

public:
  //
  bool acceptDragFiles() {
    bool rc = false;
    LONG lExStyle = GetWindowLong(m_hTarget, GWL_EXSTYLE );
    //  WS_EX_TOOLWINDOW??
    if (lExStyle & WS_EX_ACCEPTFILES) {
      rc = true;
    }
    return rc;
  }

private:

  // Internal helper function
  DWORD DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed)
  {
    DWORD dwEffect = 0;

    if(grfKeyState & MK_CONTROL) {
      dwEffect = dwAllowed & DROPEFFECT_COPY;
    }
    else if(grfKeyState & MK_SHIFT) {
      dwEffect = dwAllowed & DROPEFFECT_MOVE;
    }
  
    if(dwEffect == 0) {
      if(dwAllowed & DROPEFFECT_COPY) {
        dwEffect = DROPEFFECT_COPY;
      }
      if(dwAllowed & DROPEFFECT_MOVE) {
        dwEffect = DROPEFFECT_MOVE;
      }
    }
  
    return dwEffect;
  }


private:
  //
  // Dropping from an Explorer. We accept CF_HDROP only
  //
  bool  QueryDataObject(IDataObject *pDataObject)
  {

    FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };

    // does the data object support CF_HDROP using a HGLOBAL?
    return pDataObject->QueryGetData(&fmtetc) == S_OK ? true : false;
  }



private:
  //
  // After getting a handle for type CF_HDROP and PostMessage to
  // 
  void DropData(HWND hwnd, IDataObject *pDataObject)
  {
    //Construct a FORMATETC object
    FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };

    STGMEDIUM stgmed;

    // If the dataobject contains any HDROP stored as a HGLOBAL
    if(pDataObject->QueryGetData(&fmtetc) == S_OK)
    {

      // Found the data!
      if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK)
      {        
        //Check copy key
        BOOL removeSourceFiles = FALSE;
        short x =GetKeyState(VK_CONTROL);
        if (x <0) {
          //If CONTROL key is being pressed, then do COPY
          removeSourceFiles = FALSE;
        } else {
          //MOVE
          //If CONTROL key is not being pressed, ignore the shif-key and, do move.
          removeSourceFiles = TRUE;
        }

        SetForegroundWindow(m_hTarget);
        //Lock the stgmed.hGlobal, and get HDROP object
        HDROP hdrop = (HDROP)GlobalLock(stgmed.hGlobal);
        HWND hTarget = m_hTarget;
        if (m_hReceiver) {
          hTarget = m_hReceiver;
        }

        //SendMessage SOL specific user-defined Windows message (WM_SOL_DROPFILES) to the hTarget window.
        SendMessage(hTarget, WM_SOL_DROPFILES,
            (WPARAM)hdrop, 
            (LPARAM)removeSourceFiles);

        //Now, we can GlobalUnlock the HDROP object
        GlobalUnlock(hdrop);

        // Release the data
        ReleaseStgMedium(&stgmed);
      }
    }
  }

};


}

Last modified: 5 May 2019

Copyright (c) 2009-2019 Antillia.com ALL RIGHTS RESERVED.