OLE D&Dターゲットの実装例 (CDropTargetImpl)

(2007.06.04)
#pragma once
 
// WAC.com Class Liblary for Visual C++
// Copyright (C) WAC.com Inc. All rights reserved.
//
// This file is a part of the WAC.com Class Liblary.
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license. You must not remove this notice, or
// any other, from this software.
 
// '07.04.16 : コードの整備 (sha)
// '07.06.04 : コードの整備 (sha)
 
#include <vector>
 
// Native Compiler COM Support
#include <comdef.h>                                // _com_error
#include <comutil.h>                            // _bstr_t, _variant_t
#include <comip.h>                                // _com_ptr_t
#pragma comment(lib, "comsupp.lib")
#pragma comment(lib, "comsuppw.lib")
 
#include <ShlObj.h>
#include <ShlGuid.h>
 
#include "OleDragDropHelper.h"
 
/*
//#if (_WIN32_IE < 0x0500)
// {4657278A-411B-11d2-839A-00C04FD918D0}
DEFINE_GUID(CLSID_DragDropHelper,   0x4657278a, 0x411b, 0x11d2, 0x83, 0x9a, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0);
// {4657278B-411B-11d2-839A-00C04FD918D0}
DEFINE_GUID(IID_IDropTargetHelper,  0x4657278b, 0x411b, 0x11d2, 0x83, 0x9a, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0);
// {DE5BF786-477A-11d2-839D-00C04FD918D0}
DEFINE_GUID(IID_IDragSourceHelper,  0xde5bf786, 0x477a, 0x11d2, 0x83, 0x9d, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0);
//#endif // _WIN32_IE < 0x0500
*/
 
_COM_SMARTPTR_TYPEDEF(IDropTargetHelper, IID_IDropTargetHelper);
_COM_SMARTPTR_TYPEDEF(IDragSourceHelper, IID_IDragSourceHelper);
 
 
/////////////////////////////////////////////////////////////////////////////
// IDropTargetImpl
 
template <class T>
class ATL_NO_VTABLE IDropTargetImpl : public IDropTarget
{
public:
    IDropTargetImpl()
    {
    }
    virtual ~IDropTargetImpl()
    {
    }
 
// IDropTarget
public:
    STDMETHOD(DragEnter)(
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        return E_NOTIMPL; 
    }
    STDMETHOD(DragOver)( 
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        return E_NOTIMPL; 
    }
    STDMETHOD(DragLeave)()
    {
        return E_NOTIMPL; 
    }
    STDMETHOD(Drop)( 
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        return E_NOTIMPL; 
    }
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CDropTargetImplBase
 
template <class T>
class ATL_NO_VTABLE CDropTargetImplBase : public IDropTargetImpl<T>
{
public:
    CDropTargetImplBase()
    {
#if 1
        // Win2kのエクスプローラのツリーからのD&D時にチカチカしてしまう。。
        //  → どうも、そのウィンドが半透明処理をしてるからみたい。
        HRESULT hr = S_OK;
        
        hr = m_spDropTargetHelper.CreateInstance(CLSID_DragDropHelper);
        if (FAILED(hr))
        {
            // そのまま処理を続行する
            // → Win2k以外ではサポートされていない
        }
#endif
    }
    virtual ~CDropTargetImplBase()
    {
    }
 
// IDropTarget
public:
    STDMETHOD(DragEnter)(
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        if (pDataObj == NULL)
        {
            return E_FAIL;
        }
        if (pdwEffect == NULL)
        {
            return E_POINTER;
        }
 
        HRESULT hr = S_OK;
 
        try
        {
            // IDropTargetHelperがあれば使用する
            if (m_spDropTargetHelper)
            {
                m_spDropTargetHelper->DragEnter(pT->m_hWnd, pDataObj, &CPoint(pt.x, pt.y), *pdwEffect);
            }
 
            // ドラッグされている対象を記憶する
            m_spDataObject = pDataObj;
 
            hr = pT->OnDragEnter(pDataObj, grfKeyState, pt, pdwEffect);
            if (FAILED(hr))
            {
                m_spDataObject = NULL;
                return hr;
            }
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
    STDMETHOD(DragOver)( 
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        if (pdwEffect == NULL)
        {
            return E_POINTER;
        }
 
        HRESULT hr = S_OK;
 
        try
        {
            // IDropTargetHelperがあれば使用する
            if (m_spDropTargetHelper)
            {
                m_spDropTargetHelper->DragOver(&CPoint(pt.x, pt.y), *pdwEffect);
            }
 
            hr = pT->OnDragOver(grfKeyState, pt, pdwEffect);
            if (FAILED(hr))
            {
                m_spDataObject = NULL;
                return hr;
            }
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
    STDMETHOD(DragLeave)()
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // IDropTargetHelperがあれば使用する
            if (m_spDropTargetHelper)
            {
                m_spDropTargetHelper->DragLeave();
            }
            
            // クリアする
            m_spDataObject = NULL;
            
            hr = pT->OnDragLeave();
            if (FAILED(hr))
            {
                return hr;
            }
        }
        catch (...)
        {
            return E_FAIL;
        }
 
        return hr;
    }
    STDMETHOD(Drop)( 
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        if (pDataObj == NULL)
        {
            return E_FAIL;
        }
        if (pdwEffect == NULL)
        {
            return E_POINTER;
        }
        
        HRESULT hr = S_OK;
        
        try
        {
            // IDropTargetHelperがあれば使用する
            if (m_spDropTargetHelper)
            {
                m_spDropTargetHelper->Drop(pDataObj, &CPoint(pt.x, pt.y), *pdwEffect);
            }
 
            // ドラッグされている対象を記憶する
            m_spDataObject = pDataObj;
 
            hr = pT->OnDrop(pDataObj, grfKeyState, pt, pdwEffect);
            if (FAILED(hr))
            {
                m_spDataObject = NULL;
                return hr;
            }
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
        
        return hr;
    }
    
// Overrides
public:
    HRESULT OnDragEnter(
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        return S_OK;
    }
    HRESULT OnDragOver( 
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        return S_OK;
    }
    HRESULT OnDrop( 
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        ATLASSERT(0);
        return S_OK;
    }
    HRESULT OnDragLeave()
    {
        return S_OK;
    }
 
public:
    IDataObjectPtr GetDropDataObject()
    {
        return m_spDataObject;
    }
 
public:
    IDropTargetHelperPtr m_spDropTargetHelper;
    IDataObjectPtr m_spDataObject;
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CDropTargetImpl
 
template <class T>
class ATL_NO_VTABLE CDropTargetImpl : public CDropTargetImplBase<T>
{
public:
    CDropTargetImpl()
    {
        m_grfLastKeyState = 0;
    }
    virtual ~CDropTargetImpl()
    {
    }
 
// Overrides
public:
    HRESULT OnDragEnter(
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        // キーステートを保存する
//        ATLTRACE(_T("IDropTarget::OnDragEnter()  grfKeyState : %0x\n"), grfKeyState);
        m_grfLastKeyState = grfKeyState;
 
        IDropTargetPtr spDropTarget = pT->GetDropTarget(CPoint(pt.x, pt.y));
        if (spDropTarget == NULL)
        {
            *pdwEffect = DROPEFFECT_NONE;
            return S_OK;
        }
 
        hr = spDropTarget->DragEnter(m_spDataObject, grfKeyState, pt, pdwEffect);
        if (FAILED(hr))
        {
            return hr;
        }
 
        hr = spDropTarget->DragLeave();
        if (FAILED(hr))
        {
            return hr;
        }
 
        return hr;
    }
    HRESULT OnDragOver( 
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        // キーステートを保存する
//        ATLTRACE(_T("IDropTarget::OnDragOver()   grfKeyState : %0x\n"), grfKeyState);
        m_grfLastKeyState = grfKeyState;
 
        IDropTargetPtr spDropTarget = pT->GetDropTarget(CPoint(pt.x, pt.y));
        if (spDropTarget == NULL)
        {
            *pdwEffect = DROPEFFECT_NONE;
            return S_OK;
        }
 
        hr = spDropTarget->DragEnter(m_spDataObject, grfKeyState, pt, pdwEffect);
        if (FAILED(hr))
        {
            return hr;
        }
 
        hr = spDropTarget->DragOver(grfKeyState, pt, pdwEffect);
        if (FAILED(hr))
        {
            return hr;
        }
 
        hr = spDropTarget->DragLeave();
        if (FAILED(hr))
        {
            return hr;
        }
 
        return hr;
    }
    HRESULT OnDrop( 
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        // キーステートを保存する
//        ATLTRACE(_T("IDropTarget::OnDrop()       grfKeyState : %0x\n"), grfKeyState);
//        m_grfLastKeyState = grfKeyState;            // ここでは保存しない。。
 
//        ATLTRACE(_T("IDropTarget::OnDrop()       *pdwEffect  : %0x\n"), *pdwEffect);
 
        IDropTargetPtr spDropTarget = pT->GetDropTarget(CPoint(pt.x, pt.y));
        if (spDropTarget == NULL)
        {
            *pdwEffect = DROPEFFECT_NONE;
            return S_OK;
        }
 
        hr = spDropTarget->DragEnter(m_spDataObject, grfKeyState, pt, pdwEffect);
        if (FAILED(hr))
        {
            return hr;
        }
 
        hr = spDropTarget->DragOver(grfKeyState, pt, pdwEffect);
        if (FAILED(hr))
        {
            return hr;
        }
 
        // 左ドラッグ対応
        if (m_grfLastKeyState & MK_LBUTTON)
        {
            if ((m_grfLastKeyState & MK_CONTROL) && (m_grfLastKeyState & MK_SHIFT))
            {
                // CTRL + SHIFT = DROPEFFECT_LINK 
                *pdwEffect = DROPEFFECT_LINK;
            }
            else if (m_grfLastKeyState & MK_CONTROL)
            {
                // CTRL + DROPEFFECT_COPY 
                *pdwEffect = DROPEFFECT_COPY;
            }
            else
            {
                // No keys or SHIFT None DROPEFFECT_MOVE 
                *pdwEffect = DROPEFFECT_MOVE;
            }
        }
 
        // 右ドラッグ対応
        if (m_grfLastKeyState & MK_RBUTTON)
        {
            *pdwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
        }
 
//        ATLTRACE(_T("IDropTarget::OnDrop()       *pdwEffect  : %0x\n"), *pdwEffect);
 
        hr = spDropTarget->Drop(m_spDataObject, m_grfLastKeyState, pt, pdwEffect);
        if (FAILED(hr))
        {
            return hr;
        }
 
        return hr;
    }
    HRESULT OnDragLeave()
    {
        m_grfLastKeyState = 0;
 
        return S_OK;
    }
 
public:
    DWORD m_grfLastKeyState;
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CMultiFileDropTargetImpl
// 複数のファイルを受け入れる専用のドロップターゲット
 
template <class T>
class ATL_NO_VTABLE CMultiFileDropTargetImpl : public CDropTargetImplBase<T>
{
public:
    CMultiFileDropTargetImpl()
    {
    }
    virtual ~CMultiFileDropTargetImpl()
    {
    }
 
public:
    HRESULT OnDragEnter(
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // ファイル名を列挙する
            std::vector<CString> strFileNames;
            hr = COleDragDropHelper::EnumFileNamesFromDataObject(m_spDataObject, strFileNames);
            if (FAILED(hr) || strFileNames.size() == 0)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
    HRESULT OnDragOver( 
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // ファイル名を列挙する
            std::vector<CString> strFileNames;
            hr = COleDragDropHelper::EnumFileNamesFromDataObject(m_spDataObject, strFileNames);
            if (FAILED(hr) || strFileNames.size() == 0)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
    HRESULT OnDrop( 
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // ファイル名を列挙する
            std::vector<CString> strFileNames;
            hr = COleDragDropHelper::EnumFileNamesFromDataObject(m_spDataObject, strFileNames);
            if (FAILED(hr) || strFileNames.size() == 0)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
 
            hr = pT->OnDropFiles(strFileNames);
            if (FAILED(hr))
            {
                return hr;
            }
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CFileDropTargetImpl
// 1つのファイル(のみ)を受け入れる専用のドロップターゲット
 
template <class T>
class ATL_NO_VTABLE CFileDropTargetImpl : public CDropTargetImplBase<T>
{
public:
    CFileDropTargetImpl()
    {
    }
    virtual ~CFileDropTargetImpl()
    {
    }
 
public:
    HRESULT OnDragEnter(
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // ファイル名を列挙する
            std::vector<CString> strFileNames;
            hr = COleDragDropHelper::EnumFileNamesFromDataObject(m_spDataObject, strFileNames);
            if (FAILED(hr) || strFileNames.size() != 1)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
    HRESULT OnDragOver( 
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // ファイル名を列挙する
            std::vector<CString> strFileNames;
            hr = COleDragDropHelper::EnumFileNamesFromDataObject(m_spDataObject, strFileNames);
            if (FAILED(hr) || strFileNames.size() != 1)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
    HRESULT OnDrop( 
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // ファイル名を列挙する
            std::vector<CString> strFileNames;
            hr = COleDragDropHelper::EnumFileNamesFromDataObject(m_spDataObject, strFileNames);
            if (FAILED(hr) || strFileNames.size() != 1)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
 
            hr = pT->OnDropFile(strFileNames[0]);
            if (FAILED(hr))
            {
                return hr;
            }
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CUrlDropTargetImpl
 
template <class T>
class ATL_NO_VTABLE CUrlDropTargetImpl : public CDropTargetImplBase<T>
{
protected:
    typedef CUrlDropTargetImpl                        thisClass;
 
public:
    CUrlDropTargetImpl()
    {
    }
    virtual ~CUrlDropTargetImpl()
    {
    }
 
public:
    HRESULT OnDragEnter(
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // URLを列挙する
            std::vector<CString> strURLs;
            hr = COleDragDropHelper::EnumURLsFromDataObject(m_spDataObject, strURLs);
            if (FAILED(hr) || strURLs.size() == 0)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
    HRESULT OnDragOver( 
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // URLを列挙する
            std::vector<CString> strURLs;
            hr = COleDragDropHelper::EnumURLsFromDataObject(m_spDataObject, strURLs);
            if (FAILED(hr) || strURLs.size() == 0)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
    HRESULT OnDrop( 
        /* [unique][in] */ IDataObject* pDataObj,
        /* [in] */ DWORD grfKeyState,
        /* [in] */ POINTL pt,
        /* [out][in] */ DWORD* pdwEffect)
    {
        T* pT = static_cast<T*>(this);
 
        HRESULT hr = S_OK;
 
        try
        {
            // URLを列挙する
            std::vector<CString> strURLs;
            hr = COleDragDropHelper::EnumURLsFromDataObject(m_spDataObject, strURLs);
            if (FAILED(hr) || strURLs.size() == 0)
            {
                *pdwEffect = DROPEFFECT_NONE;
                return S_OK;
            }
 
            *pdwEffect = DROPEFFECT_COPY;
 
            hr = pT->OnDropURL(strURLs);
            if (FAILED(hr))
            {
                return hr;
            }
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
};
一覧に戻る
© 2003 WAC.com All Right Reserved.