VBoxDnDDropTarget.cpp revision 00331fbaff118e6a5077fe96327aca51a70459db
/* $Id$ */
/** @file
* VBoxDnDTarget.cpp - IDropTarget implementation.
*/
/*
* Copyright (C) 2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include <windows.h>
#include <new> /* For bad_alloc. */
#include <Shlobj.h> /* For DROPFILES and friends. */
#include "VBoxTray.h"
#include "VBoxHelpers.h"
#include "VBoxDnD.h"
#include "VBox/HostServices/DragAndDropSvc.h"
: mRefCount(1),
mdwCurEffect(0),
mcbData(0),
{
if (RT_SUCCESS(rc))
LogFlowFunc(("clientID=%RU32, rc=%Rrc\n",
}
VBoxDnDDropTarget::~VBoxDnDDropTarget(void)
{
reset();
}
/*
* IUnknown methods.
*/
{
return InterlockedIncrement(&mRefCount);
}
{
if (lCount == 0)
{
delete this;
return 0;
}
return lCount;
}
{
if ( iid == IID_IDropSource
|| iid == IID_IUnknown)
{
AddRef();
*ppvObject = this;
return S_OK;
}
*ppvObject = 0;
return E_NOINTERFACE;
}
/*
* IDropTarget methods.
*/
{
LogFlowFunc(("pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld, dwEffect=%RU32\n",
reset();
/** @todo At the moment we only support one DnD format at a time. */
/* Try different formats. CF_HDROP is the most common one, so start
* with this. */
{
}
else
{
/* So we couldn't retrieve the data in CF_HDROP format; try with
* CF_TEXT format now. Rest stays the same. */
{
}
else
{
}
}
/* Did we find a format that we support? */
{
LogFlowFunc(("Found supported format %RI16 (%s)\n",
/* Make a copy of the FORMATETC structure so that we later can
* use this for comparrison and stuff. */
/** Note: The DVTARGETDEVICE member only is a shallow copy for now! */
/* Which drop effect we're going to use? */
/* Note: pt is not used since we don't need to differentiate within our
* proxy window. */
}
else
{
/* No or incompatible data -- so no drop effect required. */
switch (hr)
{
case ERROR_INVALID_FUNCTION:
{
LogRel(("DnD: Drag'n drop format is not supported by VBoxTray\n"));
/* Enumerate supported source formats. This shouldn't happen too often
* on day to day use, but still keep it in here. */
{
LogRel(("DnD: The following formats were offered to us:\n"));
{
LogRel(("\tcfFormat=%RI16 (%s), tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n",
}
pEnumFormats->Release();
}
break;
}
default:
break;
}
}
LogFlowFunc(("Returning cfFormat=%RI16, pdwEffect=%ld, hr=%Rhrc\n",
return hr;
}
{
#ifdef DEBUG_andy
LogFlowFunc(("cfFormat=%RI16, grfKeyState=0x%x, x=%ld, y=%ld\n",
#endif
if (mFormatEtc.cfFormat)
{
/* Note: pt is not used since we don't need to differentiate within our
* proxy window. */
}
else
{
}
#ifdef DEBUG_andy
#endif
return S_OK;
}
{
#ifdef DEBUG_andy
#endif
if (mpWndParent)
mpWndParent->hide();
return S_OK;
}
{
#ifdef DEBUG
LogFlowFunc(("mFormatEtc.cfFormat=%RI16 (%s), pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
#endif
bool fCanDrop = false;
{
/* Make sure the data object's data format is still the same
* as we got it in DragEnter(). */
("Data format changed between DragEnter() and Drop(), cfFormat=%RI16 (%s), hr=%Rhrc\n",
hr));
}
int rc = VINF_SUCCESS;
{
{
/*
* First stage: Prepare the access to the storage medium.
* For now we only support HGLOBAL stuff.
*/
switch (mFormatEtc.tymed)
{
case TYMED_HGLOBAL:
if (!pvData)
{
LogFlowFunc(("Locking HGLOBAL storage failed with %Rrc\n",
}
break;
default:
AssertMsgFailed(("Storage medium type %RI32 supported\n",
mFormatEtc.tymed));
break;
}
if (RT_SUCCESS(rc))
{
/* Second stage: Do the actual copying of the data object's data,
based on the storage medium type. */
switch (mFormatEtc.cfFormat)
{
/* Handling CF_TEXT means that the system already did some marshalling
* to convert RTF or unicode text to plain ANSI text. */
case CF_TEXT:
{
if (cbSize)
{
if (RT_SUCCESS(rc))
{
}
}
break;
}
case CF_HDROP:
{
/* Convert to a string list, separated by \r\n. */
/* Get the offset of the file list. */
/* Note: This is *not* pDropFiles->pFiles! DragQueryFile only
* will work with the plain storage medium pointer! */
/* First, get the file count. */
/** @todo Does this work on Windows 2000 / NT4? */
{
NULL /* Query size first */,
0 /* cchFile */);
/* Add separation between filenames. */
if (i > 0)
{
"\r\n", 2 /* Bytes */);
if (RT_SUCCESS(rc))
}
if (RT_FAILURE(rc))
return rc;
if (fUnicode)
{
/* Allocate enough space (including terminator). */
if (pwszFile)
{
}
else
rc = VERR_NO_MEMORY;
}
else /* ANSI */
{
/* Allocate enough space (including terminator). */
if (pszFile)
{
}
else
rc = VERR_NO_MEMORY;
}
if (RT_SUCCESS(rc))
{
LogFlowFunc(("\tFile: %s (%RU32 characters)\n",
}
/* Termination. */
if (pszFile)
if (RT_FAILURE(rc))
break;
}
if (RT_SUCCESS(rc))
{
}
LogFlowFunc(("Building CF_HDROP list rc=%Rrc, pszFiles=0x%p, cFiles=%RU16, cchFiles=%RU32\n",
if (pszFiles)
break;
}
default:
AssertMsgFailed(("Format of type %RI16 (%s) not supported\n",
break;
}
}
/*
* Third stage: Release access to the storage medium again.
*/
switch (mFormatEtc.tymed)
{
case TYMED_HGLOBAL:
break;
default:
AssertMsgFailed(("Really should not happen -- see init stage!\n"));
break;
}
/* Release storage medium again. */
if (RT_SUCCESS(rc))
{
fCanDrop = true;
}
}
}
if (fCanDrop)
{
/* Note: pt is not used since we don't need to differentiate within our
* proxy window. */
}
else
if (mpWndParent)
mpWndParent->hide();
LogFlowFunc(("Returning with rc=%Rrc, mFormatEtc.cfFormat=%RI16 (%s), fCanDrop=%RTbool, *pdwEffect=%RI32\n",
return hr;
}
/* static */
{
if(grfKeyState & MK_CONTROL)
else if(grfKeyState & MK_SHIFT)
/* If there still was no drop effect assigned, check for the handed-in
* allowed effects and assign one of them.
*
* Note: A move action has precendence over a copy action! */
if (dwEffect == DROPEFFECT_NONE)
{
if (dwAllowedEffects & DROPEFFECT_COPY)
if (dwAllowedEffects & DROPEFFECT_MOVE)
}
#ifdef DEBUG_andy
LogFlowFunc(("grfKeyState=0x%x, dwAllowedEffects=0x%x, dwEffect=0x%x\n",
#endif
return dwEffect;
}
void VBoxDnDDropTarget::reset(void)
{
if (mpvData)
{
}
mcbData = 0;
mFormats = "";
}
{
return mFormats;
}
{
return rc;
}