""
参考リンク:
IDropTargetを実装する
7.IDropTargetとOLEドラッグ&ドロップ - COM研究室
まずは定型
#include <shlobj.h>
class TDropTargetBase : public IDropTarget
{
protected:
unsigned int refCount;
TDropTargetBase();
~TDropTargetBase();
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
};
TDropTargetBase::TDropTargetBase() {
refCount = 0;
};
TDropTargetBase::~TDropTargetBase() {
};
HRESULT TDropTargetBase::QueryInterface(const IID& iid, void** ppv){
if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IDropTarget))
*ppv = static_cast<IDropTarget *>(this);
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG TDropTargetBase::AddRef(){
refCount++;
return refCount;
}
ULONG TDropTargetBase::Release(){
refCount--;
if (refCount == 0) {
delete this;
}
return refCount;
}
IDropTarget::DragEnter, DragOver, DragLeave, Drop を実装する。
// TDropTargetBase は、この説明で定型の部分を分離したかっただけで、本当はクラス分けする必要性は皆無。
class TDropTarget : public TDropTargetBase
{
public:
static void CreateInstance(IDropTarget **);
private:
virtual HRESULT __stdcall DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
virtual HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
virtual HRESULT __stdcall DragLeave();
virtual HRESULT __stdcall Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
};
void TDropTarget::CreateInstance(IDropTarget **pp) {
if (pp != NULL) {
TDropTarget *p = new TDropTarget();
p->QueryInterface(IID_IDropTarget, (void **)pp);
}
}
#include <tchar.h>
#include <string>
typedef std::basic_string<TCHAR> tstring;
static void OutputDebugEffectString(DWORD *pdwEffect) {
tstring sz;
sz += TEXT("DROPEFFECT_");
if (*pdwEffect == DROPEFFECT_NONE) {
sz += TEXT("NONE");
}
else {
if (*pdwEffect & DROPEFFECT_COPY) {
sz += TEXT("COPY/");
}
if (*pdwEffect & DROPEFFECT_MOVE) {
sz += TEXT("MOVE/");
}
if (*pdwEffect & DROPEFFECT_LINK) {
sz += TEXT("LINK/");
}
if (*pdwEffect & DROPEFFECT_LINK) {
sz += TEXT("SCROLL/");
}
sz.pop_back();
}
OutputDebugString(sz.data());
}
HRESULT TDropTarget::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect){
OutputDebugString(TEXT("DragOver"));
OutputDebugEffectString(pdwEffect);
OutputDebugString(TEXT("\r\n"));
return S_OK;
}
HRESULT TDropTarget::DragOver(DWORD keyState, POINTL pt, DWORD* effect){
OutputDebugString(TEXT("DragOver"));
OutputDebugString(TEXT("\r\n"));
return S_OK;
}
HRESULT TDropTarget::DragLeave(){
OutputDebugString(TEXT("DragLeave"));
OutputDebugString(TEXT("\r\n"));
return S_OK;
}
HRESULT TDropTarget::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect){
OutputDebugString(TEXT("Drop"));
OutputDebugEffectString(pdwEffect);
OutputDebugString(TEXT("\r\n"));
return S_OK;
}
ウィンドウに割り当てる。
(ウィンドウプロシージャ内部)
case WM_CREATE:
...
{
IDropTarget *pDropTarget;
TDropTarget::CreateInstance(&pDropTarget);
RegisterDragDrop(hwnd, pDropTarget); // OLE機能にIDropTargetを登録
pDropTarget->Release();
}
...
break;
case WM_CLOSE:
...
RevokeDragDrop(hwnd);
...
break;
この時点で、もうファイルやテキストのドロップなどができる状態。
DragEnter, Drop をちゃんと実装する。
HRESULT TDropTarget::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect){
HRESULT hr;
FORMATETC formatetc;
// ドロップされようとしてるデータが CF_HDROP フォーマットをサポートしているかどうかを調べる
formatetc.cfFormat = CF_HDROP;
formatetc.ptd = NULL;
formatetc.dwAspect = DVASPECT_CONTENT;
formatetc.lindex = -1;
formatetc.tymed = TYMED_HGLOBAL;
hr = pDataObj->QueryGetData(&formatetc);
if(hr != S_OK){
*pdwEffect = DROPEFFECT_NONE;
}else{
*pdwEffect = DROPEFFECT_COPY;
}
return (*pdwEffect == DROPEFFECT_NONE) ? DRAGDROP_S_CANCEL:
S_OK;
// ちゃんと DRAGDROP_S_CANCEL を返してやらないと、DROPEFFECT_NONE にも関わらず
// Drop できてしまう。
}
static HRESULT GetDroppedFiles(IDataObject *pDataObj, std::list<tstring> *pDroppedFiles) {
HRESULT hr;
FORMATETC formatetc;
formatetc.cfFormat = CF_HDROP;
formatetc.ptd = NULL;
formatetc.dwAspect = DVASPECT_CONTENT;
formatetc.lindex = -1;
formatetc.tymed = TYMED_HGLOBAL;
hr = pDataObj->QueryGetData(&formatetc);
if (FAILED(hr)) {
goto fail;
}
STGMEDIUM medium;
hr = pDataObj->GetData(&formatetc, &medium);
if (FAILED(hr)) {
goto fail;
}
HDROP p = (HDROP)GlobalLock(medium.hGlobal);
int num = DragQueryFile(p, 0xFFFFFFFF, NULL, 0);
for (int iFile = 0; iFile < num; iFile++) {
int size = DragQueryFile(p, iFile, NULL, 0);
TCHAR * buf = new TCHAR[size + 1];
// assert(size ==
DragQueryFile(p, iFile, buf, size + 1)
// )
;
pDroppedFiles->push_back(tstring(buf));
delete[] buf;
}
GlobalUnlock(medium.hGlobal);
ReleaseStgMedium(&medium);
fail:
return hr;
}
HRESULT TDropTarget::Drop(IDataObject* pDataObj, DWORD /*grfKeyState*/, POINTL /*pt*/, DWORD* pdwEffect) {
HRESULT rc;
OutputDebugString(TEXT("Drop : "));
OutputDebugEffectString(pdwEffect);
OutputDebugString(TEXT("\r\n"));
std::list<tstring> droppedFiles;
HRESULT hr = GetDroppedFiles(pDataObj, &droppedFiles);
if (SUCCEEDED(hr) == false)
{
goto fail;
}
else
{
tstring debugString;
for(std::list<tstring>::iterator ite = droppedFiles.begin();
ite != droppedFiles.end();
ite++)
{
debugString += *ite;
debugString += TEXT("\r\n");
}
OutputDebugString(debugString.data());
}
rc = S_OK;
goto cleanUp;
fail:
rc = E_FAIL;
OutputDebugString(TEXT("Something wrong."));
cleanUp:
return rc;
}