2007-06-10 08:09:42 +00:00
|
|
|
/*
|
|
|
|
* ReactOS Explorer
|
|
|
|
*
|
|
|
|
* Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2009-10-27 10:34:16 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2007-06-10 08:09:42 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <precomp.h>
|
|
|
|
|
|
|
|
static const IDropTargetVtbl IDropTargetImpl_Vtbl;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IDropTarget
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
const IDropTargetVtbl *lpVtbl;
|
|
|
|
LONG Ref;
|
|
|
|
HWND hwndTarget;
|
|
|
|
IDropTargetHelper *DropTargetHelper;
|
|
|
|
PVOID Context;
|
|
|
|
BOOL CanDrop;
|
|
|
|
DROPTARGET_CALLBACKS Callbacks;
|
|
|
|
DWORD FormatsCount;
|
|
|
|
FORMATETC Formats[0];
|
|
|
|
} IDropTargetImpl;
|
|
|
|
|
|
|
|
static IUnknown *
|
|
|
|
IUnknown_from_impl(IDropTargetImpl *This)
|
|
|
|
{
|
|
|
|
return (IUnknown *)&This->lpVtbl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static IDropTarget *
|
|
|
|
IDropTarget_from_impl(IDropTargetImpl *This)
|
|
|
|
{
|
|
|
|
return (IDropTarget *)&This->lpVtbl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static IDropTargetImpl *
|
|
|
|
impl_from_IDropTarget(IDropTarget *iface)
|
|
|
|
{
|
|
|
|
return (IDropTargetImpl *)((ULONG_PTR)iface - FIELD_OFFSET(IDropTargetImpl,
|
|
|
|
lpVtbl));
|
|
|
|
}
|
|
|
|
|
|
|
|
static VOID
|
|
|
|
IDropTargetImpl_Free(IDropTargetImpl *This)
|
|
|
|
{
|
|
|
|
IDropTargetHelper_Release(This->DropTargetHelper);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG STDMETHODCALLTYPE
|
|
|
|
IDropTargetImpl_Release(IN OUT IDropTarget *iface)
|
|
|
|
{
|
|
|
|
IDropTargetImpl *This = impl_from_IDropTarget(iface);
|
|
|
|
ULONG Ret;
|
|
|
|
|
|
|
|
Ret = InterlockedDecrement(&This->Ref);
|
|
|
|
if (Ret == 0)
|
|
|
|
IDropTargetImpl_Free(This);
|
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG STDMETHODCALLTYPE
|
|
|
|
IDropTargetImpl_AddRef(IN OUT IDropTarget *iface)
|
|
|
|
{
|
|
|
|
IDropTargetImpl *This = impl_from_IDropTarget(iface);
|
|
|
|
|
|
|
|
return InterlockedIncrement(&This->Ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
|
|
IDropTargetImpl_QueryInterface(IN OUT IDropTarget *iface,
|
|
|
|
IN REFIID riid,
|
|
|
|
OUT LPVOID *ppvObj)
|
|
|
|
{
|
|
|
|
IDropTargetImpl *This;
|
|
|
|
|
|
|
|
if (ppvObj == NULL)
|
|
|
|
return E_POINTER;
|
|
|
|
|
|
|
|
This = impl_from_IDropTarget(iface);
|
|
|
|
|
|
|
|
if (IsEqualIID(riid,
|
|
|
|
&IID_IUnknown))
|
|
|
|
{
|
|
|
|
*ppvObj = IUnknown_from_impl(This);
|
|
|
|
}
|
|
|
|
else if (IsEqualIID(riid,
|
|
|
|
&IID_IDropTarget))
|
|
|
|
{
|
|
|
|
*ppvObj = IDropTarget_from_impl(This);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*ppvObj = NULL;
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
IDropTargetImpl_AddRef(iface);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
IDropTarget *
|
|
|
|
CreateDropTarget(IN HWND hwndTarget,
|
|
|
|
IN DWORD nSupportedFormats,
|
|
|
|
IN const FORMATETC *Formats OPTIONAL,
|
|
|
|
IN PVOID Context OPTIONAL,
|
|
|
|
IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL)
|
|
|
|
{
|
|
|
|
IDropTargetImpl *This;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
This = (IDropTargetImpl *)HeapAlloc(hProcessHeap,
|
|
|
|
0,
|
|
|
|
FIELD_OFFSET(IDropTargetImpl,
|
|
|
|
Formats[nSupportedFormats]));
|
|
|
|
if (This != NULL)
|
|
|
|
{
|
|
|
|
ZeroMemory(This,
|
|
|
|
sizeof(*This));
|
|
|
|
|
|
|
|
This->lpVtbl = &IDropTargetImpl_Vtbl;
|
|
|
|
This->Ref = 1;
|
|
|
|
This->hwndTarget = hwndTarget;
|
|
|
|
This->FormatsCount = nSupportedFormats;
|
|
|
|
if (nSupportedFormats != 0)
|
|
|
|
{
|
|
|
|
CopyMemory(This->Formats,
|
|
|
|
Formats,
|
|
|
|
sizeof(Formats[0]) * nSupportedFormats);
|
|
|
|
}
|
|
|
|
|
|
|
|
This->Context = Context;
|
|
|
|
if (Callbacks != NULL)
|
|
|
|
{
|
|
|
|
CopyMemory(&This->Callbacks,
|
|
|
|
Callbacks,
|
|
|
|
sizeof(Callbacks));
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = CoCreateInstance(&CLSID_DragDropHelper,
|
|
|
|
NULL,
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
&IID_IDropTargetHelper,
|
|
|
|
(PVOID)&This->DropTargetHelper);
|
|
|
|
|
|
|
|
if (!SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
HeapFree(hProcessHeap,
|
|
|
|
0,
|
|
|
|
This);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return IDropTarget_from_impl(This);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const FORMATETC *
|
|
|
|
IDropTargetImpl_FindSupportedFormat(IN OUT IDropTargetImpl *This,
|
|
|
|
IN IDataObject *pDataObject)
|
|
|
|
{
|
|
|
|
FORMATETC *Current, *Last;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
/* NOTE: we could use IDataObject::EnumFormatEtc(),
|
|
|
|
but this appears to be a lot easier! */
|
|
|
|
Last = This->Formats + This->FormatsCount;
|
|
|
|
for (Current = This->Formats;
|
|
|
|
Current != Last;
|
|
|
|
Current++)
|
|
|
|
{
|
|
|
|
hr = IDataObject_QueryGetData(pDataObject,
|
|
|
|
Current);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
return Current;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
|
|
IDropTargetImpl_DragEnter(IN OUT IDropTarget *iface,
|
|
|
|
IN IDataObject *pDataObject,
|
|
|
|
IN DWORD grfKeyState,
|
|
|
|
IN POINTL pt,
|
|
|
|
IN OUT DWORD *pdwEffect)
|
|
|
|
{
|
|
|
|
IDropTargetImpl *This = impl_from_IDropTarget(iface);
|
|
|
|
const FORMATETC *Format;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (pDataObject == NULL)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
This->CanDrop = FALSE;
|
|
|
|
|
|
|
|
hr = IDropTargetHelper_DragEnter(This->DropTargetHelper,
|
|
|
|
This->hwndTarget,
|
|
|
|
pDataObject,
|
2008-05-10 01:45:08 +00:00
|
|
|
(POINT *)&pt,
|
2007-06-10 08:09:42 +00:00
|
|
|
*pdwEffect);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
Format = IDropTargetImpl_FindSupportedFormat(This,
|
|
|
|
pDataObject);
|
|
|
|
if (Format != NULL)
|
|
|
|
{
|
|
|
|
/* We found a format that we support! */
|
|
|
|
if (This->Callbacks.OnDragEnter != NULL)
|
|
|
|
{
|
|
|
|
hr = This->Callbacks.OnDragEnter(iface,
|
|
|
|
This->Context,
|
|
|
|
Format,
|
|
|
|
grfKeyState,
|
|
|
|
pt,
|
|
|
|
pdwEffect);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
if (hr == S_OK)
|
|
|
|
This->CanDrop = TRUE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Special return value by the callback routine,
|
|
|
|
doesn't want to allow dragging */
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
|
|
IDropTargetImpl_DragOver(IN OUT IDropTarget *iface,
|
|
|
|
IN DWORD grfKeyState,
|
|
|
|
IN POINTL pt,
|
|
|
|
IN OUT DWORD *pdwEffect)
|
|
|
|
{
|
|
|
|
IDropTargetImpl *This = impl_from_IDropTarget(iface);
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
hr = IDropTargetHelper_DragOver(This->DropTargetHelper,
|
2008-05-10 01:45:08 +00:00
|
|
|
(POINT *)&pt,
|
2007-06-10 08:09:42 +00:00
|
|
|
*pdwEffect);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
if (This->CanDrop)
|
|
|
|
{
|
|
|
|
if (This->Callbacks.OnDragOver != NULL)
|
|
|
|
{
|
|
|
|
hr = This->Callbacks.OnDragOver(iface,
|
|
|
|
This->Context,
|
|
|
|
grfKeyState,
|
|
|
|
pt,
|
|
|
|
pdwEffect);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
if (hr != S_OK)
|
|
|
|
{
|
|
|
|
/* Special return value by the callback routine,
|
|
|
|
doesn't want to allow dropping here */
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
|
|
IDropTargetImpl_DragLeave(IN OUT IDropTarget *iface)
|
|
|
|
{
|
|
|
|
IDropTargetImpl *This = impl_from_IDropTarget(iface);
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
hr = IDropTargetHelper_DragLeave(This->DropTargetHelper);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
if (This->Callbacks.OnDragLeave != NULL)
|
|
|
|
{
|
|
|
|
hr = This->Callbacks.OnDragLeave(iface,
|
|
|
|
This->Context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
|
|
IDropTargetImpl_Drop(IN OUT IDropTarget *iface,
|
|
|
|
IN IDataObject *pDataObject,
|
|
|
|
IN DWORD grfKeyState,
|
|
|
|
IN POINTL pt,
|
|
|
|
IN OUT DWORD *pdwEffect)
|
|
|
|
{
|
|
|
|
IDropTargetImpl *This = impl_from_IDropTarget(iface);
|
|
|
|
const FORMATETC *Format;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (pDataObject == NULL)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
hr = IDropTargetHelper_Drop(This->DropTargetHelper,
|
|
|
|
pDataObject,
|
2008-05-10 01:45:08 +00:00
|
|
|
(POINT *)&pt,
|
2007-06-10 08:09:42 +00:00
|
|
|
*pdwEffect);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr) && This->CanDrop)
|
|
|
|
{
|
|
|
|
Format = IDropTargetImpl_FindSupportedFormat(This,
|
|
|
|
pDataObject);
|
|
|
|
if (Format != NULL)
|
|
|
|
{
|
|
|
|
/* We found a format that we support! */
|
|
|
|
if (This->Callbacks.OnDrop != NULL)
|
|
|
|
{
|
|
|
|
hr = This->Callbacks.OnDrop(iface,
|
|
|
|
This->Context,
|
|
|
|
Format,
|
|
|
|
grfKeyState,
|
|
|
|
pt,
|
|
|
|
pdwEffect);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
if (hr == S_OK)
|
|
|
|
This->CanDrop = TRUE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Special return value by the callback routine,
|
|
|
|
doesn't want to allow dragging */
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const IDropTargetVtbl IDropTargetImpl_Vtbl =
|
|
|
|
{
|
|
|
|
/* IUnknown */
|
|
|
|
IDropTargetImpl_QueryInterface,
|
|
|
|
IDropTargetImpl_AddRef,
|
|
|
|
IDropTargetImpl_Release,
|
|
|
|
/* IDropTarget */
|
|
|
|
IDropTargetImpl_DragEnter,
|
|
|
|
IDropTargetImpl_DragOver,
|
|
|
|
IDropTargetImpl_DragLeave,
|
|
|
|
IDropTargetImpl_Drop
|
|
|
|
};
|