OLE D&Dの登録/解除 (COleDragDropHelper)

(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>
 
/*
//#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;
    }
};
一覧に戻る
© 2003 WAC.com All Right Reserved.