IEなどのアプリケーションからドラッグアンドドロップを受け入れる

test118.gif
Microsoft WordやInternet Explorerなど多くのアプリケーションではドラッグ・アンド・ドロップによってほかのアプリケーションとデータのやり取りができるように作られている。自分で作成したアプリケーションでドラッグ・アンド・ドロップによりデータを受け取るにはIDropTargetを利用した処理を実装する。

ここではIDropTargetの実装はが簡単にできるようにCDnpDropTargetImplという補助クラスを作成した。図の例ではInternet Explorerからドラッグ・アンド・ドロップされたデータのうち、テキストデータをメッセージボックスに表示している。

自分の好みに応じた処理を実装したい場合はCDropTarget内を変更する。そのほかの部分は多くの場合、共通に利用できる。

■ATL/WTLアプリケーションうインザードでダイアログベースのプロジェクトを作成する

■自動生成したソースコードのうち「プロジェクト名.cpp」のファイルを編集して、OleInitializeとOleUninitializeが実行されるようにする

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
(...省略...)

	//ドラッグアンドドロップ用
	::OleInitialize(NULL);

	int nRet = Run(lpstrCmdLine, nCmdShow);

	//ドラッグアンドドロップ用
	::OleUninitialize();

	_Module.Term();
	::CoUninitialize();

	return nRet;
}


■MainDlg.hの先頭に以下のようなドラッグアンドドロップのメイン処理の書かれたクラス宣言を追加する

#include "DnpDropTargetImpl.h"

class CDropTarget : public CDnpDropTargetImpl
{
protected:
	virtual	bool	OnDrop(IDataObject* pDataObject,DWORD grfKeyState,POINTL pt,DWORD* pdwEffect)
	{
		//テキストのみ処理
		if(IsSupport(CF_TEXT))
		{
			bool		ret;
			CAtlString	strData;

			//テキストデータを取得
			ret = GetTextData(strData);
			if(ret)
			{
				//キー状態に応じてドラッグ・アンド・ドロップ元の動作を変えれる。
				//移動(DROPEFFECT_MOVE)にすると、ドロップ元のデータは消える。
				if(grfKeyState & MK_SHIFT)
					*pdwEffect = DROPEFFECT_MOVE;
				else
					*pdwEffect = DROPEFFECT_COPY;

				//取得文字列をメッセージボックスに表示
				::MessageBox(NULL,strData,_T(""),MB_OK);


				return	true;
			}
		}

		return	false;
	}

	virtual	bool	OnDragOver(IDataObject* pDataObject,DWORD grfKeyState,POINTL pt,DWORD* pdwEffect)
	{
		//ドラッグ元がテキスト形式(CF_TEXT)をサポートしている場合のみ処理
		if(IsSupport(CF_TEXT))
		{
			//マウスカーソルの形を指定する。キー状態に応じて設定可能
			//使用可能なキーは以下の通り
			//MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON

			//ここではシフトキーのみ監視
			if(grfKeyState & MK_SHIFT)
				*pdwEffect = DROPEFFECT_MOVE;
			else
				*pdwEffect = DROPEFFECT_COPY;

			return	true;
		}

		return	false;
	}
};


■MainDlg.hのクラスCMainDlg内にメンバ変数を追加する

	//メンバ変数追加
	CComPtr<IDropTarget>	_pIDropTarget;

■MainDlg.hのクラスCMainDlgにあるOnInitDialog関数内にドラッグアンドドロップの登録処理を追加する

LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		(...省略...)

		HRESULT	hr;
		CComObject<CDropTarget>*	pCDropTarget;

		pCDropTarget = NULL;
		hr = CComObject<CDropTarget>::CreateInstance(&pCDropTarget);

		if(SUCCEEDED(hr))
		{
			_pIDropTarget = NULL;
			hr = pCDropTarget->QueryInterface(IID_IDropTarget,(void**)&_pIDropTarget);
		}

		//ドラッグ・アンド・ドロップの受け入れ登録
		if(SUCCEEDED(hr))
			hr = ::RegisterDragDrop(m_hWnd,_pIDropTarget);

		ATLASSERT(SUCCEEDED(hr));		//失敗した場合は起動時にOleInitializeかCoInitializeを実行していない可能性大

		return TRUE;
	}

■MainDlg.hのクラスCMainDlgにあるCloseDialog関数内でRevokeDragDropを実行してドラッグアンドドロップの登録解除処理をする

	void CloseDialog(int nVal)
	{
		//ドラッグ・アンド・ドロップの受け入れ登録解除
		::RevokeDragDrop(m_hWnd);

		DestroyWindow();
		::PostQuitMessage(nVal);
	}


■ドラッグ・アンド・ドロップ用のクラス定義をファイル名「DnpDropTargetImpl.h」として保存

#pragma	once

#include "atlstr.h"


//
//
//■使用例
//
//#include "DnpDropTargetImpl.h"
//
//
/////
/////プログラム起動時にCoInitializeとOleInitializeが実行されるようにする
/////プログラム終了時にOleUninitializeとCoUninitializeが実行されるようにする
/////
//int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
//{
//	HRESULT hRes = ::CoInitialize(NULL);
//
//	(...省略...)
//
//	//ドラッグアンドドロップ用
//	::OleInitialize(NULL);
//
//	(メイン処理)
//
//	//ドラッグアンドドロップ用
//	::OleUninitialize();
//
//	::CoUninitialize();
//
//	return nRet;
//}
//
//
////
////ドラッグアンドドロップの挙動を実装したクラスを作成
////
//class CDropTarget : public CDnpDropTargetImpl
//{
//protected:
//	virtual	bool	OnDrop(IDataObject* pDataObject,DWORD grfKeyState,POINTL pt,DWORD* pdwEffect)
//	{
//		//テキストのみ処理
//		if(IsSupport(CF_TEXT))
//		{
//			bool		ret;
//			CAtlString	strData;
//
//			//テキストデータを取得
//			ret = GetTextData(strData);
//			if(ret)
//			{
//				//キー状態に応じてドラッグ・アンド・ドロップ元の動作を変えれる。
//				//移動(DROPEFFECT_MOVE)にすると、ドロップ元のデータは消える。
//				if(grfKeyState & MK_SHIFT)
//					*pdwEffect = DROPEFFECT_MOVE;
//				else
//					*pdwEffect = DROPEFFECT_COPY;
//
//				//取得文字列をメッセージボックスに表示
//				::MessageBox(NULL,strData,_T(""),MB_OK);
//
//
//				return	true;
//			}
//		}
//
//		return	false;
//	}
//
//	virtual	bool	OnDragOver(IDataObject* pDataObject,DWORD grfKeyState,POINTL pt,DWORD* pdwEffect)
//	{
//		//ドラッグ元がテキスト形式(CF_TEXT)をサポートしている場合のみ処理
//		if(IsSupport(CF_TEXT))
//		{
//			//マウスカーソルの形を指定する。キー状態に応じて設定可能
//			//使用可能なキーは以下の通り
//			//MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON
//
//			//ここではシフトキーのみ監視
//			if(grfKeyState & MK_SHIFT)
//				*pdwEffect = DROPEFFECT_MOVE;
//			else
//				*pdwEffect = DROPEFFECT_COPY;
//
//			return	true;
//		}
//
//		return	false;
//	}
//};
//
//
////
////ドラッグアンドドロップを受け入れたいウインドウに処理を追加
////
//class CMainDlg : public CDialogImpl<CMainDlg>, public CUpdateUI<CMainDlg>,
//		public CMessageFilter, public CIdleHandler
//{
//
//	//メンバ変数追加
//	CComPtr<IDropTarget>	_pIDropTarget;
//
//public:
//	(...省略...)
//
//	//ウインドウ初期化時に登録処理を追加
//	LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
//	{
//		(...省略...)
//
//
//		HRESULT	hr;
//		CComObject<CDropTarget>*	pCDropTarget;
//
//		pCDropTarget = NULL;
//		hr = CComObject<CDropTarget>::CreateInstance(&pCDropTarget);
//
//		if(SUCCEEDED(hr))
//		{
//			_pIDropTarget = NULL;
//			hr = pCDropTarget->QueryInterface(IID_IDropTarget,(void**)&_pIDropTarget);
//		}
//
//		//ドラッグ・アンド・ドロップの受け入れ登録
//		if(SUCCEEDED(hr))
//			hr = ::RegisterDragDrop(m_hWnd,_pIDropTarget);
//
//		ATLASSERT(SUCCEEDED(hr));		//失敗した場合は起動時にOleInitializeかCoInitializeを実行していない可能性大
//
//		return TRUE;
//	}
//
//	//ウインドウ終了時に登録解除処理を追加
//	void CloseDialog(int nVal)
//	{
//		//ドラッグ・アンド・ドロップの受け入れ登録解除
//		::RevokeDragDrop(m_hWnd);
//
//		DestroyWindow();
//		::PostQuitMessage(nVal);
//	}
//};
//
//
class CDnpDropTargetImpl : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CDnpDropTargetImpl>,
	public IDropTarget
{
protected:

	IDataObject*	_pIDataObject;
public:

	BEGIN_COM_MAP(CDnpDropTargetImpl)
		COM_INTERFACE_ENTRY(IDropTarget)
	END_COM_MAP()

	DECLARE_PROTECT_FINAL_CONSTRUCT()

    CDnpDropTargetImpl()
	{
		_pIDataObject = NULL;
	}


	///////////////////////////////////////
	//	IDropTargetの実装
	//


	//
	//ドラッグ・アンド・ドロップの開始
	//
	STDMETHOD(DragEnter)(IDataObject* pDataObject,DWORD grfKeyState,POINTL pt,DWORD* pdwEffect)
	{
		//_pIDataObjectにIDataObjectを保存しておく
		if(_pIDataObject)
			_pIDataObject->Release();
		_pIDataObject = NULL;
		pDataObject->QueryInterface(IID_IDataObject,(void**)&_pIDataObject);

		//以下共通処理
		return DragOver(grfKeyState,pt,pdwEffect);
	}


	//
	//ドラッグ・アンド・ドロップ中
	//
	STDMETHOD(DragOver)(DWORD grfKeyState,POINTL pt,DWORD* pdwEffect)
	{
		if(_pIDataObject == NULL || pdwEffect == NULL)
			return	E_FAIL;

		*pdwEffect = DROPEFFECT_NONE;

		return OnDragOver(_pIDataObject,grfKeyState,pt,pdwEffect) ? S_OK : E_FAIL;
	}


	//
	//ドラッグ・アンド・ドロップ終了
	//
	STDMETHOD(DragLeave)(void)
	{
		//_pIDataObjectが必要なくなったので解放
		if(_pIDataObject)
			_pIDataObject->Release();
		_pIDataObject = NULL;
		return	S_OK;
	}


	//
	//ドラッグ・アンド・ドロップ終了
	//
	STDMETHOD(Drop)(IDataObject* pDataObject,DWORD grfKeyState,POINTL pt,DWORD* pdwEffect)
	{
		bool	ret;

		//_pIDataObjectを終了時のものに変更
		if(_pIDataObject)
			_pIDataObject->Release();
		_pIDataObject = NULL;

		//GetTextData()などをOnDrop内で使えるようにQueryInterfaceが必要
		pDataObject->QueryInterface(IID_IDataObject,(void**)&_pIDataObject);

		ret = OnDrop(_pIDataObject,grfKeyState,pt,pdwEffect);

		if(_pIDataObject)
			_pIDataObject->Release();
		_pIDataObject = NULL;

		return	ret ? S_OK : E_FAIL;
	}

	//
	//	IDropTargetの実装ここまで
	///////////////////////////////////////


protected:

	virtual	bool	OnDrop(IDataObject* pDataObject,DWORD grfKeyState,POINTL pt,DWORD* pdwEffect) = 0;
	virtual	bool	OnDragOver(IDataObject* pDataObject,DWORD grfKeyState,POINTL pt,DWORD* pdwEffect) = 0;



public:


	//
	//テキストデータの取得
	//
	bool	GetTextData(CAtlString& strData)
	{
		HRESULT		hr;
		FORMATETC	sFormatEtc;
		STGMEDIUM	sStgMedium;

		strData = _T("");
		if(_pIDataObject == NULL)
			return	false;

		::ZeroMemory(&sFormatEtc,sizeof(FORMATETC));
		sFormatEtc.cfFormat	= CF_TEXT;
		sFormatEtc.dwAspect	= DVASPECT_CONTENT;
		sFormatEtc.lindex	= -1;
		sFormatEtc.tymed	= TYMED_HGLOBAL;

		hr = _pIDataObject->GetData(&sFormatEtc,&sStgMedium);
		if(FAILED(hr))
			return	false;

		strData = (char*)::GlobalLock(sStgMedium.hGlobal);
		::GlobalUnlock(sStgMedium.hGlobal);
		::ReleaseStgMedium(&sStgMedium);

		return	true;
	}



	//
	//対応形式のチェック
	//
	bool	IsSupport(CLIPFORMAT nFormat)
	{
		ULONG	i;
		ULONG	nCount;
		HRESULT	hr;
		FORMATETC		pFormatEtc[256];
		IEnumFORMATETC*	pIEnumFORMATETC;

		pIEnumFORMATETC = NULL;
		hr = _pIDataObject->EnumFormatEtc(DATADIR_GET,&pIEnumFORMATETC);
		if(FAILED(hr) || pIEnumFORMATETC == NULL)
			return	false;

		hr = pIEnumFORMATETC->Next(256,pFormatEtc,&nCount);
		if(FAILED(hr))
			return	false;

		for(i = 0; i < nCount; i++)
		{
			if(pFormatEtc[i].cfFormat == nFormat)
				return	true;
		}

		return	false;
	}
};  


プロジェクトファイルをダウンロード


カテゴリー「その他」 のエントリー