VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.4 KB
RevLine 
[50116]1/* $Id: VBoxDnDDropTarget.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBoxDnDTarget.cpp - IDropTarget implementation.
4 */
5
6/*
[98103]7 * Copyright (C) 2014-2023 Oracle and/or its affiliates.
[50116]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[50116]26 */
[69361]27
[76409]28#define LOG_GROUP LOG_GROUP_GUEST_DND
[95960]29#include <VBox/log.h>
30
[62679]31#include <iprt/win/windows.h>
[50116]32#include <new> /* For bad_alloc. */
[63311]33#include <iprt/win/shlobj.h> /* For DROPFILES and friends. */
[50116]34
35#include "VBoxTray.h"
36#include "VBoxHelpers.h"
37#include "VBoxDnD.h"
38
[50730]39#include "VBox/GuestHost/DragAndDrop.h"
[50116]40#include "VBox/HostServices/DragAndDropSvc.h"
41
[85371]42#include <iprt/path.h>
[76409]43#include <iprt/utf16.h>
[85520]44#include <iprt/uri.h>
[50116]45
46
47VBoxDnDDropTarget::VBoxDnDDropTarget(VBoxDnDWnd *pParent)
[85694]48 : m_cRefs(1),
49 m_pWndParent(pParent),
50 m_dwCurEffect(0),
51 m_pvData(NULL),
52 m_cbData(0),
53 m_EvtDrop(NIL_RTSEMEVENT)
[50116]54{
[85694]55 int rc = RTSemEventCreate(&m_EvtDrop);
[63104]56 LogFlowFunc(("rc=%Rrc\n", rc)); NOREF(rc);
[50116]57}
58
59VBoxDnDDropTarget::~VBoxDnDDropTarget(void)
60{
[50265]61 reset();
[50116]62
[85694]63 int rc2 = RTSemEventDestroy(m_EvtDrop);
[50265]64 AssertRC(rc2);
65
[85694]66 LogFlowFunc(("rc=%Rrc, mRefCount=%RI32\n", rc2, m_cRefs));
[50116]67}
68
69/*
70 * IUnknown methods.
71 */
72
73STDMETHODIMP_(ULONG) VBoxDnDDropTarget::AddRef(void)
74{
[85694]75 return InterlockedIncrement(&m_cRefs);
[50116]76}
77
78STDMETHODIMP_(ULONG) VBoxDnDDropTarget::Release(void)
79{
[85694]80 LONG lCount = InterlockedDecrement(&m_cRefs);
[50116]81 if (lCount == 0)
82 {
83 delete this;
84 return 0;
85 }
86
87 return lCount;
88}
89
90STDMETHODIMP VBoxDnDDropTarget::QueryInterface(REFIID iid, void **ppvObject)
91{
92 AssertPtrReturn(ppvObject, E_INVALIDARG);
93
94 if ( iid == IID_IDropSource
95 || iid == IID_IUnknown)
96 {
97 AddRef();
98 *ppvObject = this;
99 return S_OK;
100 }
101
102 *ppvObject = 0;
103 return E_NOINTERFACE;
104}
105
[85681]106/**
107 * Static helper function to dump supported formats of a data object.
108 *
109 * @param pDataObject Pointer to data object to dump formats for.
110 */
[59840]111/* static */
112void VBoxDnDDropTarget::DumpFormats(IDataObject *pDataObject)
113{
114 AssertPtrReturnVoid(pDataObject);
115
116 /* Enumerate supported source formats. This shouldn't happen too often
117 * on day to day use, but still keep it in here. */
118 IEnumFORMATETC *pEnumFormats;
119 HRESULT hr2 = pDataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormats);
120 if (SUCCEEDED(hr2))
121 {
122 LogRel(("DnD: The following formats were offered to us:\n"));
123
124 FORMATETC curFormatEtc;
125 while (pEnumFormats->Next(1, &curFormatEtc,
126 NULL /* pceltFetched */) == S_OK)
127 {
128 WCHAR wszCfName[128]; /* 128 chars should be enough, rest will be truncated. */
129 hr2 = GetClipboardFormatNameW(curFormatEtc.cfFormat, wszCfName,
130 sizeof(wszCfName) / sizeof(WCHAR));
131 LogRel(("\tcfFormat=%RI16 (%s), tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n",
132 curFormatEtc.cfFormat,
133 VBoxDnDDataObject::ClipboardFormatToString(curFormatEtc.cfFormat),
134 curFormatEtc.tymed,
135 curFormatEtc.dwAspect,
136 wszCfName, hr2));
137 }
138
139 pEnumFormats->Release();
140 }
141}
142
[50116]143/*
144 * IDropTarget methods.
145 */
146
[63104]147STDMETHODIMP VBoxDnDDropTarget::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
[50116]148{
[63104]149 RT_NOREF(pt);
[50116]150 AssertPtrReturn(pDataObject, E_INVALIDARG);
151 AssertPtrReturn(pdwEffect, E_INVALIDARG);
152
[50265]153 LogFlowFunc(("pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld, dwEffect=%RU32\n",
154 pDataObject, grfKeyState, pt.x, pt.y, *pdwEffect));
[50116]155
[50265]156 reset();
[50116]157
[50305]158 /** @todo At the moment we only support one DnD format at a time. */
159
[59840]160#ifdef DEBUG
161 VBoxDnDDropTarget::DumpFormats(pDataObject);
162#endif
163
164 /* Try different formats.
165 * CF_HDROP is the most common one, so start with this. */
[50265]166 FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
167 HRESULT hr = pDataObject->QueryGetData(&fmtEtc);
[50305]168 if (hr == S_OK)
[50265]169 {
[85694]170 m_strFormat = "text/uri-list";
[50305]171 }
172 else
173 {
[50561]174 LogFlowFunc(("CF_HDROP not wanted, hr=%Rhrc\n", hr));
[50116]175
[50265]176 /* So we couldn't retrieve the data in CF_HDROP format; try with
[50561]177 * CF_UNICODETEXT + CF_TEXT formats now. Rest stays the same. */
178 fmtEtc.cfFormat = CF_UNICODETEXT;
[50265]179 hr = pDataObject->QueryGetData(&fmtEtc);
[50561]180 if (hr == S_OK)
[50265]181 {
[85694]182 m_strFormat = "text/plain;charset=utf-8";
[50265]183 }
[50305]184 else
185 {
[50561]186 LogFlowFunc(("CF_UNICODETEXT not wanted, hr=%Rhrc\n", hr));
187
188 fmtEtc.cfFormat = CF_TEXT;
189 hr = pDataObject->QueryGetData(&fmtEtc);
190 if (hr == S_OK)
191 {
[85694]192 m_strFormat = "text/plain;charset=utf-8";
[50561]193 }
194 else
195 {
196 LogFlowFunc(("CF_TEXT not wanted, hr=%Rhrc\n", hr));
[59840]197 fmtEtc.cfFormat = 0; /* Set it to non-supported. */
198
199 /* Clean up. */
200 reset();
[50561]201 }
[50305]202 }
[50265]203 }
204
205 /* Did we find a format that we support? */
206 if (fmtEtc.cfFormat)
[50116]207 {
[50305]208 LogFlowFunc(("Found supported format %RI16 (%s)\n",
209 fmtEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(fmtEtc.cfFormat)));
[50265]210
211 /* Make a copy of the FORMATETC structure so that we later can
212 * use this for comparrison and stuff. */
[59840]213 /** @todo The DVTARGETDEVICE member only is a shallow copy for now! */
[85694]214 memcpy(&m_FormatEtc, &fmtEtc, sizeof(FORMATETC));
[50265]215
[50116]216 /* Which drop effect we're going to use? */
217 /* Note: pt is not used since we don't need to differentiate within our
218 * proxy window. */
219 *pdwEffect = VBoxDnDDropTarget::GetDropEffect(grfKeyState, *pdwEffect);
220 }
221 else
222 {
223 /* No or incompatible data -- so no drop effect required. */
224 *pdwEffect = DROPEFFECT_NONE;
[50265]225
226 switch (hr)
227 {
228 case ERROR_INVALID_FUNCTION:
229 {
[55180]230 LogRel(("DnD: Drag and drop format is not supported by VBoxTray\n"));
[59840]231 VBoxDnDDropTarget::DumpFormats(pDataObject);
[50265]232 break;
233 }
234
235 default:
236 break;
237 }
[50116]238 }
239
[59840]240 LogFlowFunc(("Returning mstrFormats=%s, cfFormat=%RI16, pdwEffect=%ld, hr=%Rhrc\n",
[85694]241 m_strFormat.c_str(), fmtEtc.cfFormat, *pdwEffect, hr));
[50116]242 return hr;
243}
244
245STDMETHODIMP VBoxDnDDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
246{
[63104]247 RT_NOREF(pt);
[50116]248 AssertPtrReturn(pdwEffect, E_INVALIDARG);
249
250#ifdef DEBUG_andy
[50265]251 LogFlowFunc(("cfFormat=%RI16, grfKeyState=0x%x, x=%ld, y=%ld\n",
[85694]252 m_FormatEtc.cfFormat, grfKeyState, pt.x, pt.y));
[50116]253#endif
254
[85694]255 if (m_FormatEtc.cfFormat)
[50116]256 {
257 /* Note: pt is not used since we don't need to differentiate within our
258 * proxy window. */
259 *pdwEffect = VBoxDnDDropTarget::GetDropEffect(grfKeyState, *pdwEffect);
260 }
261 else
262 {
263 *pdwEffect = DROPEFFECT_NONE;
264 }
265
266#ifdef DEBUG_andy
[50177]267 LogFlowFunc(("Returning *pdwEffect=%ld\n", *pdwEffect));
[50116]268#endif
269 return S_OK;
270}
271
272STDMETHODIMP VBoxDnDDropTarget::DragLeave(void)
273{
274#ifdef DEBUG_andy
[85694]275 LogFlowFunc(("cfFormat=%RI16\n", m_FormatEtc.cfFormat));
[50116]276#endif
277
[85694]278 if (m_pWndParent)
279 m_pWndParent->Hide();
[50116]280
281 return S_OK;
282}
283
[63104]284STDMETHODIMP VBoxDnDDropTarget::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
[50116]285{
[63104]286 RT_NOREF(pt);
[50116]287 AssertPtrReturn(pDataObject, E_INVALIDARG);
[59840]288 AssertPtrReturn(pdwEffect, E_INVALIDARG);
[50116]289
[50305]290 LogFlowFunc(("mFormatEtc.cfFormat=%RI16 (%s), pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
[85694]291 m_FormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(m_FormatEtc.cfFormat),
[50305]292 pDataObject, grfKeyState, pt.x, pt.y));
[59840]293
[50265]294 HRESULT hr = S_OK;
295
[85694]296 if (m_FormatEtc.cfFormat) /* Did we get a supported format yet? */
[50116]297 {
[59840]298 /* Make sure the data object's data format is still valid. */
[85694]299 hr = pDataObject->QueryGetData(&m_FormatEtc);
[50265]300 AssertMsg(SUCCEEDED(hr),
[59840]301 ("Data format changed to invalid between DragEnter() and Drop(), cfFormat=%RI16 (%s), hr=%Rhrc\n",
[85694]302 m_FormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(m_FormatEtc.cfFormat), hr));
[50265]303 }
304
[50305]305 int rc = VINF_SUCCESS;
306
[50265]307 if (SUCCEEDED(hr))
308 {
[50177]309 STGMEDIUM stgMed;
[85694]310 hr = pDataObject->GetData(&m_FormatEtc, &stgMed);
[50265]311 if (SUCCEEDED(hr))
[50116]312 {
[50265]313 /*
314 * First stage: Prepare the access to the storage medium.
315 * For now we only support HGLOBAL stuff.
316 */
317 PVOID pvData = NULL; /** @todo Put this in an own union? */
[50116]318
[85694]319 switch (m_FormatEtc.tymed)
[50265]320 {
321 case TYMED_HGLOBAL:
322 pvData = GlobalLock(stgMed.hGlobal);
323 if (!pvData)
324 {
325 LogFlowFunc(("Locking HGLOBAL storage failed with %Rrc\n",
326 RTErrConvertFromWin32(GetLastError())));
[50305]327 rc = VERR_INVALID_HANDLE;
328 hr = E_INVALIDARG; /* Set special hr for OLE. */
[50265]329 }
330 break;
331
332 default:
333 AssertMsgFailed(("Storage medium type %RI32 supported\n",
[85694]334 m_FormatEtc.tymed));
[50305]335 rc = VERR_NOT_SUPPORTED;
336 hr = DV_E_TYMED; /* Set special hr for OLE. */
[50265]337 break;
338 }
339
[50305]340 if (RT_SUCCESS(rc))
[50265]341 {
[59840]342 /*
343 * Second stage: Do the actual copying of the data object's data,
344 * based on the storage medium type.
345 */
[85694]346 switch (m_FormatEtc.cfFormat)
[50265]347 {
[59840]348 case CF_TEXT:
[74364]349 RT_FALL_THROUGH();
[50561]350 case CF_UNICODETEXT:
351 {
352 AssertPtr(pvData);
353 size_t cbSize = GlobalSize(pvData);
[74364]354
355 LogRel(("DnD: Got %zu bytes of %s\n", cbSize,
[85694]356 m_FormatEtc.cfFormat == CF_TEXT
[74364]357 ? "ANSI text" : "Unicode text"));
[50561]358 if (cbSize)
359 {
360 char *pszText = NULL;
[59840]361
[85694]362 rc = m_FormatEtc.cfFormat == CF_TEXT
[59840]363 /* ANSI codepage -> UTF-8 */
364 ? RTStrCurrentCPToUtf8(&pszText, (char *)pvData)
365 /* Unicode -> UTF-8 */
366 : RTUtf16ToUtf8((PCRTUTF16)pvData, &pszText);
367
[50561]368 if (RT_SUCCESS(rc))
369 {
[59840]370 AssertPtr(pszText);
[50561]371
[59840]372 size_t cbText = strlen(pszText) + 1; /* Include termination. */
[50561]373
[85694]374 m_pvData = RTMemDup((void *)pszText, cbText);
375 m_cbData = cbText;
[50561]376
[59840]377 RTStrFree(pszText);
378 pszText = NULL;
[50305]379 }
380 }
[50265]381
382 break;
383 }
384
385 case CF_HDROP:
[50305]386 {
387 AssertPtr(pvData);
388
389 /* Convert to a string list, separated by \r\n. */
390 DROPFILES *pDropFiles = (DROPFILES *)pvData;
391 AssertPtr(pDropFiles);
392
[80847]393 /** @todo Replace / merge the following code with VBoxShClWinDropFilesToStringList(). */
[78516]394
[74364]395 /* Do we need to do Unicode stuff? */
396 const bool fUnicode = RT_BOOL(pDropFiles->fWide);
397
[50305]398 /* Get the offset of the file list. */
399 Assert(pDropFiles->pFiles >= sizeof(DROPFILES));
[74364]400
[50305]401 /* Note: This is *not* pDropFiles->pFiles! DragQueryFile only
402 * will work with the plain storage medium pointer! */
403 HDROP hDrop = (HDROP)(pvData);
404
405 /* First, get the file count. */
406 /** @todo Does this work on Windows 2000 / NT4? */
[85520]407 char *pszFiles = NULL;
408 size_t cchFiles = 0;
[74364]409 UINT cFiles = DragQueryFile(hDrop, UINT32_MAX /* iFile */, NULL /* lpszFile */, 0 /* cchFile */);
[50305]410
[74365]411 LogRel(("DnD: Got %RU16 file(s), fUnicode=%RTbool\n", cFiles, fUnicode));
[74364]412
[50305]413 for (UINT i = 0; i < cFiles; i++)
414 {
[74364]415 UINT cchFile = DragQueryFile(hDrop, i /* File index */, NULL /* Query size first */, 0 /* cchFile */);
416 Assert(cchFile);
[50305]417
418 if (RT_FAILURE(rc))
[50399]419 break;
[50305]420
[74364]421 char *pszFileUtf8 = NULL; /* UTF-8 version. */
422 UINT cchFileUtf8 = 0;
[50305]423 if (fUnicode)
424 {
425 /* Allocate enough space (including terminator). */
[74364]426 WCHAR *pwszFile = (WCHAR *)RTMemAlloc((cchFile + 1) * sizeof(WCHAR));
[50305]427 if (pwszFile)
428 {
[74448]429 const UINT cwcFileUtf16 = DragQueryFileW(hDrop, i /* File index */,
[74364]430 pwszFile, cchFile + 1 /* Include terminator */);
431
[74448]432 AssertMsg(cwcFileUtf16 == cchFile, ("cchFileUtf16 (%RU16) does not match cchFile (%RU16)\n",
433 cwcFileUtf16, cchFile));
434 RT_NOREF(cwcFileUtf16);
[74364]435
436 rc = RTUtf16ToUtf8(pwszFile, &pszFileUtf8);
[74448]437 if (RT_SUCCESS(rc))
438 {
439 cchFileUtf8 = (UINT)strlen(pszFileUtf8);
440 Assert(cchFileUtf8);
441 }
[57297]442
443 RTMemFree(pwszFile);
[50305]444 }
445 else
446 rc = VERR_NO_MEMORY;
447 }
448 else /* ANSI */
449 {
450 /* Allocate enough space (including terminator). */
[74364]451 pszFileUtf8 = (char *)RTMemAlloc((cchFile + 1) * sizeof(char));
452 if (pszFileUtf8)
[50305]453 {
[74364]454 cchFileUtf8 = DragQueryFileA(hDrop, i /* File index */,
455 pszFileUtf8, cchFile + 1 /* Include terminator */);
456
457 AssertMsg(cchFileUtf8 == cchFile, ("cchFileUtf8 (%RU16) does not match cchFile (%RU16)\n",
458 cchFileUtf8, cchFile));
[50305]459 }
460 else
461 rc = VERR_NO_MEMORY;
462 }
463
464 if (RT_SUCCESS(rc))
465 {
[74364]466 LogFlowFunc(("\tFile: %s (cchFile=%RU16)\n", pszFileUtf8, cchFileUtf8));
467
468 LogRel(("DnD: Adding guest file '%s'\n", pszFileUtf8));
469
[50399]470 if (RT_SUCCESS(rc))
[85371]471 {
[85520]472 char *pszFileURI = RTUriFileCreate(pszFileUtf8);
473 if (pszFileURI)
474 {
475 const size_t cchFileURI = RTStrNLen(pszFileURI, RTPATH_MAX);
476 rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, pszFileURI, cchFileURI);
477 if (RT_SUCCESS(rc))
478 cchFiles += cchFileURI;
479
480 RTStrFree(pszFileURI);
481 }
482 else
483 rc = VERR_NO_MEMORY;
[85371]484 }
[50305]485 }
[85371]486
487 if (RT_FAILURE(rc))
[74448]488 LogRel(("DnD: Error handling file entry #%u, rc=%Rrc\n", i, rc));
[50305]489
[85371]490 RTStrFree(pszFileUtf8);
[50305]491
[50561]492 if (RT_SUCCESS(rc))
[85520]493 {
494 /* Add separation between filenames.
495 * Note: Also do this for the last element of the list. */
[85746]496 rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, DND_PATH_SEPARATOR_STR, 2 /* Bytes */);
[85520]497 if (RT_SUCCESS(rc))
498 cchFiles += 2; /* Include \r\n */
499 }
[50305]500 }
501
502 if (RT_SUCCESS(rc))
503 {
[50830]504 cchFiles += 1; /* Add string termination. */
[50305]505
[85520]506 const size_t cbFiles = cchFiles * sizeof(char);
507
508 LogFlowFunc(("cFiles=%u, cchFiles=%zu, cbFiles=%zu, pszFiles=0x%p\n",
[50830]509 cFiles, cchFiles, cbFiles, pszFiles));
510
[85694]511 m_pvData = pszFiles;
512 m_cbData = cbFiles;
[50305]513 }
[85371]514 else
515 {
516 RTStrFree(pszFiles);
517 pszFiles = NULL;
518 }
[50305]519
[85371]520 LogFlowFunc(("Building CF_HDROP list rc=%Rrc, cFiles=%RU16, cchFiles=%RU32\n",
521 rc, cFiles, cchFiles));
[50265]522 break;
[50305]523 }
[50265]524
525 default:
[50399]526 /* Note: Should not happen due to the checks done in DragEnter(). */
[50305]527 AssertMsgFailed(("Format of type %RI16 (%s) not supported\n",
[85694]528 m_FormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(m_FormatEtc.cfFormat)));
[50305]529 hr = DV_E_CLIPFORMAT; /* Set special hr for OLE. */
[50265]530 break;
531 }
532
[50399]533 /*
[50830]534 * Third stage: Unlock + release access to the storage medium again.
[50399]535 */
[85694]536 switch (m_FormatEtc.tymed)
[50399]537 {
538 case TYMED_HGLOBAL:
539 GlobalUnlock(stgMed.hGlobal);
540 break;
[50265]541
[50399]542 default:
543 AssertMsgFailed(("Really should not happen -- see init stage!\n"));
544 break;
545 }
[50265]546 }
547
[50830]548 /* Release storage medium again. */
549 ReleaseStgMedium(&stgMed);
550
[50399]551 /* Signal waiters. */
[85694]552 m_rcDropped = rc;
553 RTSemEventSignal(m_EvtDrop);
[50116]554 }
555 }
556
[50399]557 if (RT_SUCCESS(rc))
[50116]558 {
559 /* Note: pt is not used since we don't need to differentiate within our
560 * proxy window. */
561 *pdwEffect = VBoxDnDDropTarget::GetDropEffect(grfKeyState, *pdwEffect);
562 }
563 else
564 *pdwEffect = DROPEFFECT_NONE;
565
[85694]566 if (m_pWndParent)
567 m_pWndParent->Hide();
[50265]568
[50399]569 LogFlowFunc(("Returning with hr=%Rhrc (%Rrc), mFormatEtc.cfFormat=%RI16 (%s), *pdwEffect=%RI32\n",
[85694]570 hr, rc, m_FormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(m_FormatEtc.cfFormat),
[50399]571 *pdwEffect));
[50305]572
[50265]573 return hr;
[50116]574}
575
[85681]576/**
577 * Static helper function to return a drop effect for a given key state and allowed effects.
578 *
579 * @returns Resolved drop effect.
580 * @param grfKeyState Key state to determine drop effect for.
581 * @param dwAllowedEffects Allowed drop effects to determine drop effect for.
582 */
[50116]583/* static */
584DWORD VBoxDnDDropTarget::GetDropEffect(DWORD grfKeyState, DWORD dwAllowedEffects)
585{
586 DWORD dwEffect = DROPEFFECT_NONE;
587
588 if(grfKeyState & MK_CONTROL)
589 dwEffect = dwAllowedEffects & DROPEFFECT_COPY;
590 else if(grfKeyState & MK_SHIFT)
591 dwEffect = dwAllowedEffects & DROPEFFECT_MOVE;
592
593 /* If there still was no drop effect assigned, check for the handed-in
594 * allowed effects and assign one of them.
595 *
596 * Note: A move action has precendence over a copy action! */
597 if (dwEffect == DROPEFFECT_NONE)
598 {
599 if (dwAllowedEffects & DROPEFFECT_COPY)
600 dwEffect = DROPEFFECT_COPY;
601 if (dwAllowedEffects & DROPEFFECT_MOVE)
602 dwEffect = DROPEFFECT_MOVE;
603 }
604
605#ifdef DEBUG_andy
[50177]606 LogFlowFunc(("grfKeyState=0x%x, dwAllowedEffects=0x%x, dwEffect=0x%x\n",
607 grfKeyState, dwAllowedEffects, dwEffect));
[50116]608#endif
609 return dwEffect;
610}
611
[85681]612/**
613 * Resets a drop target object.
614 */
[50265]615void VBoxDnDDropTarget::reset(void)
616{
617 LogFlowFuncEnter();
618
[85694]619 if (m_pvData)
[50265]620 {
[85694]621 RTMemFree(m_pvData);
622 m_pvData = NULL;
[50265]623 }
624
[85694]625 m_cbData = 0;
[59840]626
[85694]627 RT_ZERO(m_FormatEtc);
628 m_strFormat = "";
[50265]629}
630
[85681]631/**
632 * Returns the currently supported formats of a drop target.
633 *
634 * @returns Supported formats.
635 */
[59840]636RTCString VBoxDnDDropTarget::Formats(void) const
[50305]637{
[85694]638 return m_strFormat;
[50305]639}
640
[85681]641/**
642 * Waits for a drop event to happen.
643 *
644 * @returns VBox status code.
645 * @param msTimeout Timeout (in ms) to wait for drop event.
646 */
[50265]647int VBoxDnDDropTarget::WaitForDrop(RTMSINTERVAL msTimeout)
648{
649 LogFlowFunc(("msTimeout=%RU32\n", msTimeout));
[50399]650
[85694]651 int rc = RTSemEventWait(m_EvtDrop, msTimeout);
[50399]652 if (RT_SUCCESS(rc))
[85694]653 rc = m_rcDropped;
[50399]654
[50265]655 LogFlowFuncLeaveRC(rc);
656 return rc;
657}
658
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use