#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;
}
};