#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>
/*
//#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);
class CStgMedium : public STGMEDIUM
{
public:
CStgMedium()
{
::ZeroMemory(this, sizeof(STGMEDIUM));
}
virtual ~CStgMedium()
{
::ReleaseStgMedium(this);
}
};
/////////////////////////////////////////////////////////////////////////////
// COleDragDropHelper
class COleDragDropHelper
{
protected:
COleDragDropHelper(); // 実装しない
virtual ~COleDragDropHelper();
public:
static HRESULT Register(HWND hWnd, IUnknownPtr spUnk)
{
HRESULT hr = S_OK;
// CoLockObjectExternal()する前にチェックしてしまう
IDropTargetPtr spDropTarget = spUnk;
if (spDropTarget == NULL)
{
return E_FAIL;
}
hr = ::CoLockObjectExternal(spUnk, TRUE, FALSE);
if (FAILED(hr))
{
return hr;
}
hr = ::RegisterDragDrop(hWnd, spDropTarget);
if (FAILED(hr))
{
::CoLockObjectExternal(spUnk, FALSE, FALSE);
return hr;
}
return hr;
}
static HRESULT Revoke(HWND hWnd, IUnknownPtr spUnk)
{
HRESULT hr = S_OK;
hr = ::RevokeDragDrop(hWnd);
if (FAILED(hr))
{
// 無視する。。
}
hr = ::CoLockObjectExternal(spUnk, FALSE, TRUE);
if (FAILED(hr))
{
// 無視する。。
}
return hr;
}
public:
// shell32.dll version 6.0 or later
static HRESULT Emulate_SHDoDragDrop(HWND hwnd, IDataObject* pdtobj, IDropSource* pdsrc, DWORD dwEffect, DWORD* pdwEffect)
{
HRESULT hr = S_OK;
IDragSourceHelperPtr spDragSourceHelper;
hr = spDragSourceHelper.CreateInstance(CLSID_DragDropHelper);
if (FAILED(hr))
{
// そのまま処理を続行する
// → Win2k以外ではサポートされていない
}
// IDragSourceHelperがあれば使用する
if (spDragSourceHelper)
{
POINT pt = {0, 0};
::GetCursorPos(&pt);
::ScreenToClient(hwnd, &pt);
hr = spDragSourceHelper->InitializeFromWindow(hwnd, &pt, pdtobj);
if (FAILED(hr))
{
// 無視する。。
}
}
return ::DoDragDrop(pdtobj, pdsrc, dwEffect, pdwEffect);
}
public:
// IDataObjectから、ファイルを列挙する
static HRESULT EnumFileNamesFromDataObject(IDataObjectPtr spDataObject, std::vector<CString>& strFileNames)
{
if (spDataObject == NULL)
{
ATLASSERT(0);
return E_FAIL;
}
HRESULT hr = S_OK;
CStgMedium medium; // クラスなので、自分で解放してくれる
FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
hr = spDataObject->GetData(&fe, &medium);
if (FAILED(hr))
{
return hr;
}
int nCount = ::DragQueryFile((HDROP)medium.hGlobal, -1, NULL, 0);
// ファイル名を列挙する
for (int i = 0; i < nCount; i++)
{
TCHAR szPath[_MAX_PATH] = { 0 };
::DragQueryFile((HDROP)medium.hGlobal, i, szPath, _countof(szPath));
strFileNames.push_back(szPath);
}
return S_OK;
}
// IDataObjectから、URLを列挙する
static HRESULT EnumURLsFromDataObject(IDataObjectPtr spDataObject, std::vector<CString>& strURLs)
{
USES_CONVERSION;
if (spDataObject == NULL)
{
ATLASSERT(0);
return E_FAIL;
}
HRESULT hr = S_OK;
UINT CF_SHELLURL = ::RegisterClipboardFormat(CFSTR_SHELLURL);
if (CF_SHELLURL == 0)
{
return E_FAIL;
}
FORMATETC fe = {CF_SHELLURL, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
hr = spDataObject->QueryGetData(&fe);
if (FAILED(hr))
{
return hr;
}
CStgMedium medium; // クラスなので、自分で解放してくれる
hr = spDataObject->GetData(&fe, &medium);
if (FAILED(hr))
{
return hr;
}
// CF_TEXTと同じNULL終端されたANSIテキストで格納されています
// TODO: pBufとか省略しない。。pBufferにする
CHAR* pBuf = (CHAR*)::GlobalLock(medium.hGlobal);
CString strURL = A2T(pBuf);
::GlobalUnlock(medium.hGlobal);
if (strURL.IsEmpty())
{
return E_FAIL;
}
strURLs.push_back(strURL);
return S_OK;
}
};