1/*
2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#pragma push_macro("bad_alloc")
27//"bad_alloc" would be introduced in STL as "std::zbad_alloc" and discarded by linker
28//by this action we avoid the conflict with AWT implementation of "bad_alloc"
29//we need <new> inclusion for STL "new" oprators set.
30#define bad_alloc zbad_alloc
31#include <new>
32
33#if defined(_DEBUG) || defined(DEBUG)
34extern void * operator new(size_t size, const char * filename, int linenumber);
35void * operator new(size_t size) {return operator new(size, "stl", 1);}
36#endif
37#include <map>
38
39#pragma pop_macro("bad_alloc")
40//"bad_alloc" is undefined from here
41
42#include <awt.h>
43#include <shlobj.h>
44
45#include "jlong.h"
46#include "awt_DataTransferer.h"
47#include "awt_DnDDS.h"
48#include "awt_DnDDT.h"
49#include "awt_Cursor.h"
50#include "awt_Toolkit.h"
51#include "awt_Component.h"
52
53#include "java_awt_event_InputEvent.h"
54#include "java_awt_dnd_DnDConstants.h"
55#include "sun_awt_windows_WDragSourceContextPeer.h"
56
57#include "awt_ole.h"
58#include "awt_DCHolder.h"
59
60bool operator < (const FORMATETC &fr, const FORMATETC &fl) {
61    return memcmp(&fr, &fl, sizeof(FORMATETC)) < 0;
62}
63
64typedef std::map<FORMATETC, STGMEDIUM> CDataMap;
65
66#define GALLOCFLG (GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT)
67#define JAVA_BUTTON_MASK (java_awt_event_InputEvent_BUTTON1_DOWN_MASK | \
68                          java_awt_event_InputEvent_BUTTON2_DOWN_MASK | \
69                          java_awt_event_InputEvent_BUTTON3_DOWN_MASK)
70
71extern "C" {
72DWORD __cdecl convertActionsToDROPEFFECT(jint actions);
73jint  __cdecl convertDROPEFFECTToActions(DWORD effects);
74}
75
76class PictureDragHelper
77{
78private:
79    static CDataMap st;
80    static IDragSourceHelper *pHelper;
81public:
82    static HRESULT Create(
83        JNIEnv* env,
84        jintArray imageData,
85        int imageWidth,
86        int imageHeight,
87        int anchorX,
88        int anchorY,
89        IDataObject *pIDataObject)
90    {
91        if (NULL == imageData) {
92            return S_FALSE;
93        }
94        OLE_TRY
95        OLE_HRT( CoCreateInstance(
96            CLSID_DragDropHelper,
97            NULL,
98            CLSCTX_ALL,
99            IID_IDragSourceHelper,
100            (LPVOID*)&pHelper))
101
102        jintArray ia = imageData;
103        jsize iPointCoint = env->GetArrayLength(ia);
104
105        DCHolder ph;
106        ph.Create(NULL, imageWidth, imageHeight, TRUE);
107        env->GetIntArrayRegion(ia, 0, iPointCoint, (jint*)ph.m_pPoints);
108
109        SHDRAGIMAGE sdi;
110        sdi.sizeDragImage.cx = imageWidth;
111        sdi.sizeDragImage.cy = imageHeight;
112        sdi.ptOffset.x = anchorX;
113        sdi.ptOffset.y = anchorY;
114        sdi.crColorKey = 0xFFFFFFFF;
115        sdi.hbmpDragImage = ph;
116
117        // this call assures that the bitmap will be dragged around
118        OLE_HR = pHelper->InitializeFromBitmap(
119            &sdi,
120            pIDataObject
121        );
122        // in case of an error we need to destroy the image, else the helper object takes ownership
123        if (FAILED(OLE_HR)) {
124            DeleteObject(sdi.hbmpDragImage);
125        }
126        OLE_CATCH
127        OLE_RETURN_HR
128    }
129
130    static void Destroy()
131    {
132        if (NULL!=pHelper) {
133            CleanFormatMap();
134            pHelper->Release();
135            pHelper = NULL;
136        }
137    }
138
139    static void CleanFormatMap()
140    {
141        for (CDataMap::iterator i = st.begin(); st.end() != i; i = st.erase(i)) {
142            ::ReleaseStgMedium(&i->second);
143        }
144    }
145    static void SetData(const FORMATETC &format, const STGMEDIUM &medium)
146    {
147        CDataMap::iterator i = st.find(format);
148        if (st.end() != i) {
149            ::ReleaseStgMedium(&i->second);
150            i->second = medium;
151        } else {
152            st[format] = medium;
153        }
154    }
155    static const FORMATETC *FindFormat(const FORMATETC &format)
156    {
157        static FORMATETC fm = {0};
158        CDataMap::iterator i = st.find(format);
159        if (st.end() != i) {
160            return &i->first;
161        }
162        for (i = st.begin(); st.end() != i; ++i) {
163            if (i->first.cfFormat==format.cfFormat) {
164                return &i->first;
165            }
166        }
167        return NULL;
168    }
169    static STGMEDIUM *FindData(const FORMATETC &format)
170    {
171        CDataMap::iterator i = st.find(format);
172        if (st.end() != i) {
173            return &i->second;
174        }
175        for (i = st.begin(); st.end() != i; ++i) {
176            const FORMATETC &f = i->first;
177            if (f.cfFormat==format.cfFormat && (f.tymed == (f.tymed & format.tymed))) {
178                return &i->second;
179            }
180        }
181        return NULL;
182    }
183};
184
185
186CDataMap PictureDragHelper::st;
187IDragSourceHelper *PictureDragHelper::pHelper = NULL;
188
189extern const CLIPFORMAT CF_PERFORMEDDROPEFFECT = ::RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
190extern const CLIPFORMAT CF_FILEGROUPDESCRIPTORW = ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
191extern const CLIPFORMAT CF_FILEGROUPDESCRIPTORA = ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
192extern const CLIPFORMAT CF_FILECONTENTS = ::RegisterClipboardFormat(CFSTR_FILECONTENTS);
193
194typedef struct {
195    AwtDragSource* dragSource;
196    jobject        cursor;
197    jintArray      imageData;
198    jint           imageWidth;
199    jint           imageHeight;
200    jint           x;
201    jint           y;
202} StartDragRec;
203
204/**
205 * StartDrag
206 */
207
208void AwtDragSource::StartDrag(
209    AwtDragSource* self,
210    jobject cursor,
211    jintArray imageData,
212    jint imageWidth,
213    jint imageHeight,
214    jint x,
215    jint y)
216{
217    StartDragRec* sdrp = new StartDragRec;
218    sdrp->dragSource = self;
219    sdrp->imageData = imageData;
220    sdrp->cursor = cursor;
221    sdrp->imageWidth = imageWidth;
222    sdrp->imageHeight = imageHeight;
223    sdrp->x = x;
224    sdrp->y = y;
225
226    AwtToolkit::GetInstance().WaitForSingleObject(self->m_mutex);
227
228    AwtToolkit::GetInstance().InvokeFunctionLater((void (*)(void *))&AwtDragSource::_DoDragDrop, (void *)sdrp);
229
230    self->WaitUntilSignalled(FALSE);
231}
232
233/**
234 * DoDragDrop - called from message pump thread
235 */
236
237void AwtDragSource::_DoDragDrop(void* param) {
238    StartDragRec*  sdrp         = (StartDragRec*)param;
239    AwtDragSource* dragSource   = sdrp->dragSource;
240    DWORD          effects      = DROPEFFECT_NONE;
241    JNIEnv*        env          = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
242    jobject        peer         = env->NewLocalRef(dragSource->GetPeer());
243
244    if (sdrp->imageData) {
245        PictureDragHelper::Create(
246            env,
247            sdrp->imageData,
248            sdrp->imageWidth,
249            sdrp->imageHeight,
250            sdrp->x,
251            sdrp->y,
252            (IDataObject*)dragSource);
253        env->DeleteGlobalRef(sdrp->imageData);
254    }
255    dragSource->SetCursor(sdrp->cursor);
256    env->DeleteGlobalRef(sdrp->cursor);
257    delete sdrp;
258
259    HRESULT        res;
260
261    // StartDrag has caused dragSource->m_mutex to be held by our thread now
262
263    AwtDropTarget::SetCurrentDnDDataObject(dragSource);
264
265    ::GetCursorPos(&dragSource->m_dragPoint);
266
267    dragSource->Signal();
268
269    AwtToolkit &toolkit = AwtToolkit::GetInstance();
270    toolkit.isInDoDragDropLoop = TRUE;
271    res = ::DoDragDrop(dragSource,
272                       dragSource,
273                       convertActionsToDROPEFFECT(dragSource->m_actions),
274                       &effects
275          );
276    toolkit.isInDoDragDropLoop = FALSE;
277
278    if (effects == DROPEFFECT_NONE && dragSource->m_dwPerformedDropEffect != DROPEFFECT_NONE) {
279        effects = dragSource->m_dwPerformedDropEffect;
280    }
281    dragSource->m_dwPerformedDropEffect = DROPEFFECT_NONE;
282
283    call_dSCddfinished(env, peer, res == DRAGDROP_S_DROP && effects != DROPEFFECT_NONE,
284                       convertDROPEFFECTToActions(effects),
285                       dragSource->m_dragPoint.x, dragSource->m_dragPoint.y);
286
287    env->DeleteLocalRef(peer);
288
289    DASSERT(AwtDropTarget::IsCurrentDnDDataObject(dragSource));
290    AwtDropTarget::SetCurrentDnDDataObject(NULL);
291
292    PictureDragHelper::Destroy();
293    dragSource->Release();
294}
295
296/**
297 * constructor
298 */
299
300AwtDragSource::AwtDragSource(JNIEnv* env, jobject peer, jobject component,
301                             jobject transferable, jobject trigger,
302                             jint actions, jlongArray formats,
303                             jobject formatMap) {
304    m_peer      = env->NewGlobalRef(peer);
305
306    m_refs      = 1;
307
308    m_actions   = actions;
309
310    m_ntypes    = 0;
311
312    m_initmods  = 0;
313    m_lastmods  = 0;
314
315    m_droptarget   = NULL;
316    m_enterpending = TRUE;
317
318    m_cursor     = NULL;
319
320    m_mutex      = ::CreateMutex(NULL, FALSE, NULL);
321
322    m_component     = env->NewGlobalRef(component);
323    m_transferable  = env->NewGlobalRef(transferable);
324    m_formatMap     = env->NewGlobalRef(formatMap);
325
326    m_dragPoint.x = 0;
327    m_dragPoint.y = 0;
328
329    m_fNC         = TRUE;
330    m_dropPoint.x = 0;
331    m_dropPoint.y = 0;
332
333    m_dwPerformedDropEffect = DROPEFFECT_NONE;
334    m_bRestoreNodropCustomCursor = FALSE;
335
336    LoadCache(formats);
337}
338
339/**
340 * destructor
341 */
342
343AwtDragSource::~AwtDragSource() {
344    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
345
346    // fix for 6212440: on application shutdown, this object's
347    // destruction might be suppressed due to dangling COM references.
348    // On destruction, VM might be shut down already, so we should make
349    // a null check on env.
350    if (env) {
351        env->DeleteGlobalRef(m_peer);
352        env->DeleteGlobalRef(m_component);
353        env->DeleteGlobalRef(m_transferable);
354        env->DeleteGlobalRef(m_formatMap);
355    }
356
357    ::CloseHandle(m_mutex);
358
359    UnloadCache();
360}
361
362/**
363 * _compar
364 *
365 * compare format's then tymed's .... only one tymed bit may be set
366 * at any time in a FORMATETC in the cache.
367 */
368
369int AwtDragSource::_compar(const void* first, const void* second) {
370    FORMATETC *fp = (FORMATETC *)first;
371    FORMATETC *sp = (FORMATETC *)second;
372    int      r  = fp->cfFormat - sp->cfFormat;
373
374    return r != 0 ? r : fp->tymed - sp->tymed;
375}
376
377/**
378 * LoadCache
379 */
380
381void AwtDragSource::LoadCache(jlongArray formats) {
382    JNIEnv*      env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
383    unsigned int items = 0;
384    unsigned int i = 0;
385    unsigned int idx = 0;
386
387    if (m_types != (FORMATETC *)NULL) {
388        UnloadCache();
389    }
390
391    items = env->GetArrayLength(formats);
392
393    if (items == 0) {
394        return;
395    }
396
397    jboolean isCopy;
398    jlong *lFormats = env->GetLongArrayElements(formats, &isCopy),
399        *saveFormats = lFormats;
400
401    for (i = 0, m_ntypes = 0; i < items; i++, lFormats++) {
402        // Warning C4244.
403        // Cast from jlong to CLIPFORMAT (WORD).
404        CLIPFORMAT fmt = (CLIPFORMAT)*lFormats;
405        switch (fmt) {
406        case CF_ENHMETAFILE:
407            m_ntypes++;    // Only TYMED_ENHMF
408            break;
409        case CF_METAFILEPICT:
410            m_ntypes++;    // Only TYMED_MFPICT
411            break;
412        case CF_HDROP:
413            m_ntypes++;    // Only TYMED_HGLOBAL
414            break;
415        default:
416            m_ntypes += 2; // TYMED_HGLOBAL and TYMED_ISTREAM
417            break;
418        }
419    }
420
421    try {
422        m_types = (FORMATETC *)safe_Calloc(sizeof(FORMATETC), m_ntypes);
423    } catch (std::bad_alloc&) {
424        m_ntypes = 0;
425        throw;
426    }
427
428    lFormats = saveFormats;
429
430    for (i = 0, idx = 0; i < items; i++, lFormats++) {
431        // Warning C4244.
432        // Cast from jlong to CLIPFORMAT (WORD).
433        CLIPFORMAT fmt = (CLIPFORMAT)*lFormats;
434
435        m_types[idx].cfFormat = fmt;
436        m_types[idx].dwAspect = DVASPECT_CONTENT;
437        m_types[idx].lindex   = -1;
438
439        switch (fmt) {
440        default:
441            m_types[idx].tymed = TYMED_ISTREAM;
442            idx++;
443
444            // now make a copy, but with a TYMED of HGLOBAL
445            m_types[idx] = m_types[idx-1];
446            m_types[idx].tymed = TYMED_HGLOBAL;
447            idx++;
448            break;
449        case CF_HDROP:
450            m_types[idx].tymed = TYMED_HGLOBAL;
451            idx++;
452            break;
453        case CF_ENHMETAFILE:
454            m_types[idx].tymed = TYMED_ENHMF;
455            idx++;
456            break;
457        case CF_METAFILEPICT:
458            m_types[idx].tymed = TYMED_MFPICT;
459            idx++;
460            break;
461        }
462    }
463    DASSERT(idx == m_ntypes);
464
465    env->ReleaseLongArrayElements(formats, saveFormats, 0);
466
467    // sort them in ascending order of format
468    qsort((void *)m_types, (size_t)m_ntypes, (size_t)sizeof(FORMATETC),
469          _compar);
470}
471
472/**
473 * UnloadCache
474 */
475
476void AwtDragSource::UnloadCache() {
477    if (m_ntypes == 0) {
478        return;
479    }
480
481    free((void*)m_types);
482    m_ntypes = 0;
483    m_types  = (FORMATETC *)NULL;
484}
485
486/**
487 * ChangeCursor
488 */
489HRESULT AwtDragSource::ChangeCursor()
490{
491    if (m_cursor != NULL) {
492        ::SetCursor(m_cursor->GetHCursor());
493        return S_OK;
494    }
495    return DRAGDROP_S_USEDEFAULTCURSORS;
496}
497
498/**
499 * SetCursor
500 */
501void AwtDragSource::SetCursor(jobject cursor) {
502    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
503
504    if (JNU_IsNull(env, cursor)) {
505        m_cursor = NULL;
506        return;
507    }
508
509    jlong pData = env->GetLongField(cursor, AwtCursor::pDataID);
510    // Warning C4312.
511    // Cast jlong (__int64) to pointer.
512    m_cursor = (AwtCursor*)pData;
513
514    if (m_cursor == NULL) {
515        m_cursor = AwtCursor::CreateSystemCursor(cursor);
516    }
517}
518
519/**
520 * MatchFormatEtc
521 */
522
523HRESULT __stdcall
524AwtDragSource::MatchFormatEtc(FORMATETC __RPC_FAR *pFormatEtcIn,
525                              FORMATETC *cacheEnt) {
526    TRY;
527
528    const FORMATETC *pFormat = PictureDragHelper::FindFormat(*pFormatEtcIn);
529    if (NULL != pFormat) {
530        if (NULL != cacheEnt) {
531            *cacheEnt = *pFormat;
532        }
533        return S_OK;
534    }
535
536    if ((pFormatEtcIn->tymed & (TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ENHMF |
537                                TYMED_MFPICT)) == 0) {
538        return DV_E_TYMED;
539    } else if (pFormatEtcIn->lindex != -1) {
540        return DV_E_LINDEX;
541    } else if (pFormatEtcIn->dwAspect != DVASPECT_CONTENT) {
542        return DV_E_DVASPECT;
543    }
544
545    FORMATETC tmp = *pFormatEtcIn;
546
547    static const DWORD supportedTymeds[] =
548        { TYMED_ISTREAM, TYMED_HGLOBAL, TYMED_ENHMF, TYMED_MFPICT };
549    static const int nSupportedTymeds = 4;
550
551    for (int i = 0; i < nSupportedTymeds; i++) {
552        /*
553         * Fix for BugTraq Id 4426805.
554         * Match only if the tymed is supported by the requester.
555         */
556        if ((pFormatEtcIn->tymed & supportedTymeds[i]) == 0) {
557            continue;
558        }
559
560        tmp.tymed = supportedTymeds[i];
561        pFormat = (const FORMATETC *)bsearch((const void *)&tmp,
562                                             (const void *)m_types,
563                                             (size_t)      m_ntypes,
564                                             (size_t)      sizeof(FORMATETC),
565                                                           _compar
566                                             );
567        if (NULL != pFormat) {
568            if (cacheEnt != (FORMATETC *)NULL) {
569                *cacheEnt = *pFormat;
570            }
571            return S_OK;
572        }
573    }
574
575    return DV_E_FORMATETC;
576
577    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
578}
579
580/**
581 * QueryInterface
582 */
583
584HRESULT __stdcall AwtDragSource::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) {
585    TRY;
586
587    if (riid == IID_IUnknown) {
588        *ppvObject = (void __RPC_FAR *__RPC_FAR)(IUnknown*)(IDropSource*)this;
589        AddRef();
590        return S_OK;
591    } else if (riid == IID_IDropSource) {
592        *ppvObject = (void __RPC_FAR *__RPC_FAR)(IDropSource*)this;
593        AddRef();
594        return S_OK;
595    } else if (riid == IID_IDataObject) {
596        *ppvObject = (void __RPC_FAR *__RPC_FAR)(IDataObject*)this;
597        AddRef();
598        return S_OK;
599    } else {
600        *ppvObject = (void __RPC_FAR *__RPC_FAR)NULL;
601        return E_NOINTERFACE;
602    }
603
604    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
605}
606
607/**
608 * AddRef
609 */
610
611ULONG __stdcall AwtDragSource::AddRef() {
612    return (ULONG)++m_refs;
613}
614
615/**
616 * Release
617 */
618
619ULONG __stdcall AwtDragSource::Release() {
620    int refs;
621
622    if ((refs = --m_refs) == 0) delete this;
623
624    return (ULONG)refs;
625}
626
627/**
628 * QueryContinueDrag
629 */
630
631HRESULT __stdcall  AwtDragSource::QueryContinueDrag(BOOL fEscapeKeyPressed, DWORD grfKeyState) {
632    AwtToolkit::GetInstance().eventNumber++;
633    TRY;
634
635    JNIEnv* env       = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
636
637    if (fEscapeKeyPressed)
638        return DRAGDROP_S_CANCEL;
639
640    jint modifiers = AwtComponent::GetJavaModifiers();
641
642    POINT dragPoint;
643
644    ::GetCursorPos(&dragPoint);
645
646    if ( (dragPoint.x != m_dragPoint.x || dragPoint.y != m_dragPoint.y) &&
647         m_lastmods == modifiers) {//cannot move before cursor change
648        call_dSCmouseMoved(env, m_peer,
649                           m_actions, modifiers, dragPoint.x, dragPoint.y);
650        JNU_CHECK_EXCEPTION_RETURN(env, E_UNEXPECTED);
651        m_dragPoint = dragPoint;
652    }
653
654    if ((modifiers & JAVA_BUTTON_MASK) == 0) {
655        return DRAGDROP_S_DROP;
656    } else if (m_initmods == 0) {
657        m_initmods = modifiers;
658    } else if ((modifiers & JAVA_BUTTON_MASK) != (m_initmods & JAVA_BUTTON_MASK)) {
659        return DRAGDROP_S_CANCEL;
660    } else if (m_lastmods != modifiers) {
661        call_dSCchanged(env, m_peer,
662                        m_actions, modifiers, dragPoint.x, dragPoint.y);
663        m_bRestoreNodropCustomCursor = TRUE;
664    }
665
666    m_lastmods = modifiers;
667
668    //CR 6480706 - MS Bug on hold
669    HCURSOR hNeedCursor;
670    if (
671        m_bRestoreNodropCustomCursor &&
672        m_cursor != NULL &&
673        (hNeedCursor = m_cursor->GetHCursor()) != ::GetCursor() )
674    {
675        ChangeCursor();
676        m_bRestoreNodropCustomCursor = FALSE;
677    }
678    return S_OK;
679
680   CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
681}
682
683/**
684 * GiveFeedback
685 */
686
687HRESULT __stdcall  AwtDragSource::GiveFeedback(DWORD dwEffect) {
688    AwtToolkit::GetInstance().eventNumber++;
689    TRY;
690
691    JNIEnv* env       = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
692    jint    modifiers = 0;
693    SHORT   mods = 0;
694
695    m_actions = convertDROPEFFECTToActions(dwEffect);
696
697    if (::GetKeyState(VK_LBUTTON) & 0xff00) {
698        mods |= MK_LBUTTON;
699    } else if (::GetKeyState(VK_MBUTTON) & 0xff00) {
700        mods |= MK_MBUTTON;
701    } else if (::GetKeyState(VK_RBUTTON) & 0xff00) {
702        mods |= MK_RBUTTON;
703    }
704
705    if (::GetKeyState(VK_SHIFT)   & 0xff00)
706        mods |= MK_SHIFT;
707    if (::GetKeyState(VK_CONTROL) & 0xff00)
708        mods |= MK_CONTROL;
709    if (::GetKeyState(VK_MENU) & 0xff00)
710        mods |= MK_ALT;
711
712    modifiers = AwtComponent::GetJavaModifiers();
713
714    POINT curs;
715
716    ::GetCursorPos(&curs);
717
718    m_droptarget = ::WindowFromPoint(curs);
719
720    int invalid = (dwEffect == DROPEFFECT_NONE);
721
722    if (invalid) {
723        // Don't call dragExit if dragEnter and dragOver haven't been called.
724        if (!m_enterpending) {
725            call_dSCexit(env, m_peer, curs.x, curs.y);
726        }
727        m_droptarget = (HWND)NULL;
728        m_enterpending = TRUE;
729    } else if (m_droptarget != NULL) {
730        (*(m_enterpending ? call_dSCenter : call_dSCmotion))
731            (env, m_peer, m_actions, modifiers, curs.x, curs.y);
732
733        m_enterpending = FALSE;
734    }
735
736    if (m_droptarget != NULL) {
737        RECT  rect;
738        POINT client = curs;
739        VERIFY(::ScreenToClient(m_droptarget, &client));
740        VERIFY(::GetClientRect(m_droptarget, &rect));
741        if (::PtInRect(&rect, client)) {
742            m_fNC = FALSE;
743            m_dropPoint = client;
744        } else {
745            m_fNC = TRUE;
746            m_dropPoint = curs;
747        }
748    } else {
749        m_fNC = TRUE;
750        m_dropPoint.x = 0;
751        m_dropPoint.y = 0;
752    }
753
754    m_bRestoreNodropCustomCursor = (dwEffect == DROPEFFECT_NONE);
755
756    return ChangeCursor();
757
758    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
759}
760
761
762/**
763 * GetData
764 */
765
766HRESULT __stdcall AwtDragSource::GetData(FORMATETC __RPC_FAR *pFormatEtc,
767                                         STGMEDIUM __RPC_FAR *pmedium) {
768    AwtToolkit::GetInstance().eventNumber++;
769    TRY;
770    STGMEDIUM *pPicMedia = PictureDragHelper::FindData(*pFormatEtc);
771    if (NULL != pPicMedia) {
772        *pmedium = *pPicMedia;
773        //return  outside, so AddRef the instance of pstm or hGlobal!
774        if (pmedium->tymed == TYMED_ISTREAM) {
775            pmedium->pstm->AddRef();
776            pmedium->pUnkForRelease = (IUnknown *)NULL;
777        } else if (pmedium->tymed == TYMED_HGLOBAL) {
778            AddRef();
779            pmedium->pUnkForRelease = (IDropSource *)this;
780        }
781        return S_OK;
782    }
783
784    HRESULT res = GetProcessId(pFormatEtc, pmedium);
785    if (res == S_OK) {
786        return res;
787    }
788
789    FORMATETC matchedFormatEtc;
790    res = MatchFormatEtc(pFormatEtc, &matchedFormatEtc);
791    if (res != S_OK) {
792        return res;
793    }
794
795    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
796
797    if (env->PushLocalFrame(2) < 0) {
798        return E_OUTOFMEMORY;
799    }
800
801    jbyteArray bytes =
802        AwtDataTransferer::ConvertData(env, m_component, m_transferable,
803                                       (jlong)matchedFormatEtc.cfFormat,
804                                       m_formatMap);
805    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
806        env->ExceptionDescribe();
807        env->ExceptionClear();
808        env->PopLocalFrame(NULL);
809        return E_UNEXPECTED;
810    }
811    if (bytes == NULL) {
812        env->PopLocalFrame(NULL);
813        return E_UNEXPECTED;
814    }
815
816    jint nBytes = env->GetArrayLength(bytes);
817
818    if ((matchedFormatEtc.tymed & TYMED_ISTREAM) != 0) {
819        ADSIStreamProxy *istream = new ADSIStreamProxy(this, bytes, nBytes);
820
821        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
822            env->ExceptionDescribe();
823            env->ExceptionClear();
824            env->PopLocalFrame(NULL);
825            return E_UNEXPECTED;
826        }
827
828        pmedium->tymed = TYMED_ISTREAM;
829        pmedium->pstm = istream;
830        pmedium->pUnkForRelease = (IUnknown *)NULL;
831
832        env->PopLocalFrame(NULL);
833        return S_OK;
834    } else if ((matchedFormatEtc.tymed & TYMED_HGLOBAL) != 0) {
835        HGLOBAL copy = ::GlobalAlloc(GALLOCFLG, nBytes +
836                                     ((matchedFormatEtc.cfFormat == CF_HDROP)
837                                          ? sizeof(DROPFILES)
838                                          : 0));
839        if (copy == NULL) {
840            env->PopLocalFrame(NULL);
841            throw std::bad_alloc();
842        }
843
844        char *dataout = (char *)::GlobalLock(copy);
845
846        if (matchedFormatEtc.cfFormat == CF_HDROP) {
847            DROPFILES *dropfiles = (DROPFILES *)dataout;
848            dropfiles->pFiles = sizeof(DROPFILES);
849            dropfiles->pt.x = m_dropPoint.x;
850            dropfiles->pt.y = m_dropPoint.y;
851            dropfiles->fNC = m_fNC;
852            dropfiles->fWide = TRUE; // we publish only Unicode
853            dataout += sizeof(DROPFILES);
854        }
855
856        env->GetByteArrayRegion(bytes, 0, nBytes, (jbyte *)dataout);
857        ::GlobalUnlock(copy);
858
859        pmedium->tymed = TYMED_HGLOBAL;
860        pmedium->hGlobal = copy;
861        pmedium->pUnkForRelease = (IUnknown *)NULL;
862
863        env->PopLocalFrame(NULL);
864        return S_OK;
865    } else if ((matchedFormatEtc.tymed & TYMED_ENHMF) != 0) {
866        LPBYTE lpbEmfBuffer =
867            (LPBYTE)env->GetPrimitiveArrayCritical(bytes, NULL);
868        if (lpbEmfBuffer == NULL) {
869            env->PopLocalFrame(NULL);
870            throw std::bad_alloc();
871        }
872
873        HENHMETAFILE hemf = ::SetEnhMetaFileBits(nBytes, lpbEmfBuffer);
874
875        env->ReleasePrimitiveArrayCritical(bytes, (LPVOID)lpbEmfBuffer, JNI_ABORT);
876
877        if (hemf == NULL) {
878            env->PopLocalFrame(NULL);
879            return E_UNEXPECTED;
880        }
881
882        pmedium->tymed = TYMED_ENHMF;
883        pmedium->hEnhMetaFile = hemf;
884        pmedium->pUnkForRelease = (IUnknown *)NULL;
885
886        env->PopLocalFrame(NULL);
887        return S_OK;
888    } else if ((matchedFormatEtc.tymed & TYMED_MFPICT) != 0) {
889        LPBYTE lpbMfpBuffer =
890            (LPBYTE)env->GetPrimitiveArrayCritical(bytes, NULL);
891        if (lpbMfpBuffer == NULL) {
892            env->PopLocalFrame(NULL);
893            throw std::bad_alloc();
894        }
895
896        HMETAFILE hmf = ::SetMetaFileBitsEx(nBytes - sizeof(METAFILEPICT),
897                                         lpbMfpBuffer + sizeof(METAFILEPICT));
898        if (hmf == NULL) {
899            env->ReleasePrimitiveArrayCritical(bytes, (LPVOID)lpbMfpBuffer, JNI_ABORT);
900            env->PopLocalFrame(NULL);
901            return E_UNEXPECTED;
902        }
903
904        LPMETAFILEPICT lpMfpOld = (LPMETAFILEPICT)lpbMfpBuffer;
905
906        HMETAFILEPICT hmfp = ::GlobalAlloc(GALLOCFLG, sizeof(METAFILEPICT));
907        if (hmfp == NULL) {
908            VERIFY(::DeleteMetaFile(hmf));
909            env->ReleasePrimitiveArrayCritical(bytes, (LPVOID)lpbMfpBuffer, JNI_ABORT);
910            env->PopLocalFrame(NULL);
911            throw std::bad_alloc();
912        }
913
914        LPMETAFILEPICT lpMfp = (LPMETAFILEPICT)::GlobalLock(hmfp);
915        lpMfp->mm = lpMfpOld->mm;
916        lpMfp->xExt = lpMfpOld->xExt;
917        lpMfp->yExt = lpMfpOld->yExt;
918        lpMfp->hMF = hmf;
919        ::GlobalUnlock(hmfp);
920
921        env->ReleasePrimitiveArrayCritical(bytes, (LPVOID)lpbMfpBuffer, JNI_ABORT);
922
923        pmedium->tymed = TYMED_MFPICT;
924        pmedium->hMetaFilePict = hmfp;
925        pmedium->pUnkForRelease = (IUnknown *)NULL;
926
927        env->PopLocalFrame(NULL);
928        return S_OK;
929    }
930
931    env->PopLocalFrame(NULL);
932    return DV_E_TYMED;
933
934    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
935}
936
937/**
938 * GetDataHere
939 */
940
941HRESULT __stdcall AwtDragSource::GetDataHere(FORMATETC __RPC_FAR *pFormatEtc,
942                                             STGMEDIUM __RPC_FAR *pmedium) {
943    AwtToolkit::GetInstance().eventNumber++;
944    TRY;
945
946    if (pmedium->pUnkForRelease != (IUnknown *)NULL) {
947        return E_INVALIDARG;
948    }
949
950    HRESULT res = GetProcessId(pFormatEtc, pmedium);
951    if (res == S_OK) {
952        return res;
953    }
954
955    FORMATETC matchedFormatEtc;
956    res = MatchFormatEtc(pFormatEtc, &matchedFormatEtc);
957    if (res != S_OK) {
958        return res;
959    }
960
961    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
962
963    if (env->PushLocalFrame(2) < 0) {
964        return E_OUTOFMEMORY;
965    }
966
967    jbyteArray bytes =
968        AwtDataTransferer::ConvertData(env, m_component, m_transferable,
969                                       (jlong)matchedFormatEtc.cfFormat,
970                                       m_formatMap);
971    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
972        env->ExceptionDescribe();
973        env->ExceptionClear();
974        env->PopLocalFrame(NULL);
975        return E_UNEXPECTED;
976    }
977    if (bytes == NULL) {
978        env->PopLocalFrame(NULL);
979        return E_UNEXPECTED;
980    }
981
982    jint nBytes = env->GetArrayLength(bytes);
983
984    // NOTE: TYMED_ENHMF and TYMED_MFPICT are not valid for GetDataHere().
985    if ((matchedFormatEtc.tymed & TYMED_ISTREAM) != 0) {
986        jboolean isCopy;
987        jbyte *bBytes = env->GetByteArrayElements(bytes, &isCopy);
988        if (bBytes == NULL) {
989            env->PopLocalFrame(NULL);
990            return E_UNEXPECTED;
991        }
992
993        ULONG act;
994        HRESULT res = pmedium->pstm->Write((const void *)bBytes, (ULONG)nBytes,
995                                           &act);
996
997        env->ReleaseByteArrayElements(bytes, bBytes, JNI_ABORT);
998
999        env->PopLocalFrame(NULL);
1000        return S_OK;
1001    } else if ((matchedFormatEtc.tymed & TYMED_HGLOBAL) != 0) {
1002        ::SetLastError(0); // clear error
1003        // Warning C4244.
1004        SIZE_T mBytes = ::GlobalSize(pmedium->hGlobal);
1005        if (::GetLastError() != 0) {
1006            env->PopLocalFrame(NULL);
1007            return E_UNEXPECTED;
1008        }
1009
1010        if (nBytes + ((matchedFormatEtc.cfFormat == CF_HDROP)
1011                        ? sizeof(DROPFILES) : 0) > mBytes) {
1012            env->PopLocalFrame(NULL);
1013            return STG_E_MEDIUMFULL;
1014        }
1015
1016        char *dataout = (char *)::GlobalLock(pmedium->hGlobal);
1017
1018        if (matchedFormatEtc.cfFormat == CF_HDROP) {
1019            DROPFILES *dropfiles = (DROPFILES *)dataout;
1020            dropfiles->pFiles = sizeof(DROPFILES);
1021            dropfiles->pt.x = m_dropPoint.x;
1022            dropfiles->pt.y = m_dropPoint.y;
1023            dropfiles->fNC = m_fNC;
1024            dropfiles->fWide = TRUE; // good guess!
1025            dataout += sizeof(DROPFILES);
1026        }
1027
1028        env->GetByteArrayRegion(bytes, 0, nBytes, (jbyte *)dataout);
1029        ::GlobalUnlock(pmedium->hGlobal);
1030
1031        env->PopLocalFrame(NULL);
1032        return S_OK;
1033    }
1034
1035    env->PopLocalFrame(NULL);
1036    return DV_E_TYMED;
1037
1038    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1039}
1040
1041/**
1042 * QueryGetData
1043 */
1044
1045HRESULT __stdcall  AwtDragSource::QueryGetData(FORMATETC __RPC_FAR *pFormatEtc) {
1046    AwtToolkit::GetInstance().eventNumber++;
1047    TRY;
1048
1049    return MatchFormatEtc(pFormatEtc, (FORMATETC *)NULL);
1050
1051    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1052}
1053
1054
1055/**
1056 * GetCanonicalFormatEtc
1057 */
1058
1059HRESULT __stdcall  AwtDragSource::GetCanonicalFormatEtc(FORMATETC __RPC_FAR *pFormatEtcIn, FORMATETC __RPC_FAR *pFormatEtcOut) {
1060    AwtToolkit::GetInstance().eventNumber++;
1061    TRY;
1062
1063    HRESULT   res = MatchFormatEtc(pFormatEtcIn, (FORMATETC *)NULL);
1064
1065    if (res != S_OK) return res;
1066
1067    *pFormatEtcOut = *pFormatEtcIn;
1068
1069    pFormatEtcOut->ptd = NULL;
1070
1071    return DATA_S_SAMEFORMATETC;
1072
1073    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1074}
1075
1076/**
1077 * SetData
1078 */
1079
1080HRESULT __stdcall AwtDragSource::SetData(FORMATETC __RPC_FAR *pFormatEtc, STGMEDIUM __RPC_FAR *pmedium, BOOL fRelease) {
1081    AwtToolkit::GetInstance().eventNumber++;
1082    if (pFormatEtc->cfFormat == CF_PERFORMEDDROPEFFECT && pmedium->tymed == TYMED_HGLOBAL) {
1083        m_dwPerformedDropEffect = *(DWORD*)::GlobalLock(pmedium->hGlobal);
1084        ::GlobalUnlock(pmedium->hGlobal);
1085        if (fRelease) {
1086            ::ReleaseStgMedium(pmedium);
1087        }
1088        return S_OK;
1089    }
1090
1091    if (fRelease) {
1092        //we are copying pmedium as a structure for further use, so no any release!
1093        PictureDragHelper::SetData(*pFormatEtc, *pmedium);
1094        return S_OK;
1095    }
1096    return E_UNEXPECTED;
1097}
1098
1099/**
1100 * EnumFormatEtc
1101 */
1102
1103HRESULT __stdcall  AwtDragSource::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC *__RPC_FAR *ppenumFormatEtc) {
1104    AwtToolkit::GetInstance().eventNumber++;
1105    TRY;
1106
1107    *ppenumFormatEtc = new ADSIEnumFormatEtc(this);
1108    return S_OK;
1109
1110    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1111}
1112
1113/**
1114 * DAdvise
1115 */
1116
1117HRESULT __stdcall  AwtDragSource::DAdvise(FORMATETC __RPC_FAR *pFormatEtc, DWORD advf, IAdviseSink __RPC_FAR *pAdvSink, DWORD __RPC_FAR *pdwConnection) {
1118    AwtToolkit::GetInstance().eventNumber++;
1119    return E_NOTIMPL;
1120}
1121
1122/**
1123 * DUnadvise
1124 */
1125
1126HRESULT __stdcall  AwtDragSource::DUnadvise(DWORD dwConnection) {
1127    AwtToolkit::GetInstance().eventNumber++;
1128    return OLE_E_ADVISENOTSUPPORTED;
1129}
1130
1131/**
1132 * EnumAdvise
1133 */
1134
1135HRESULT __stdcall  AwtDragSource::EnumDAdvise(IEnumSTATDATA __RPC_FAR *__RPC_FAR *ppenumAdvise) {
1136    AwtToolkit::GetInstance().eventNumber++;
1137    return OLE_E_ADVISENOTSUPPORTED;
1138}
1139
1140const UINT AwtDragSource::PROCESS_ID_FORMAT =
1141    ::RegisterClipboardFormat(TEXT("_SUNW_JAVA_AWT_PROCESS_ID"));
1142
1143HRESULT __stdcall AwtDragSource::GetProcessId(FORMATETC __RPC_FAR *pFormatEtc, STGMEDIUM __RPC_FAR *pmedium) {
1144    AwtToolkit::GetInstance().eventNumber++;
1145    if ((pFormatEtc->tymed & TYMED_HGLOBAL) == 0) {
1146        return DV_E_TYMED;
1147    } else if (pFormatEtc->lindex != -1) {
1148        return DV_E_LINDEX;
1149    } else if (pFormatEtc->dwAspect != DVASPECT_CONTENT) {
1150        return DV_E_DVASPECT;
1151    } else if (pFormatEtc->cfFormat != PROCESS_ID_FORMAT) {
1152        return DV_E_FORMATETC;
1153    }
1154
1155    DWORD id = ::CoGetCurrentProcess();
1156
1157    HGLOBAL copy = ::GlobalAlloc(GALLOCFLG, sizeof(id));
1158
1159    if (copy == NULL) {
1160        throw std::bad_alloc();
1161    }
1162
1163    char *dataout = (char *)::GlobalLock(copy);
1164
1165    memcpy(dataout, &id, sizeof(id));
1166    ::GlobalUnlock(copy);
1167
1168    pmedium->tymed = TYMED_HGLOBAL;
1169    pmedium->hGlobal = copy;
1170    pmedium->pUnkForRelease = (IUnknown *)NULL;
1171
1172    return S_OK;
1173}
1174
1175DECLARE_JAVA_CLASS(dSCClazz, "sun/awt/windows/WDragSourceContextPeer")
1176
1177void
1178AwtDragSource::call_dSCenter(JNIEnv* env, jobject self, jint targetActions,
1179                             jint modifiers, jint x, jint y) {
1180    DECLARE_VOID_JAVA_METHOD(dSCenter, dSCClazz, "dragEnter", "(IIII)V");
1181    DASSERT(!JNU_IsNull(env, self));
1182    env->CallVoidMethod(self, dSCenter, targetActions, modifiers, x, y);
1183    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
1184        env->ExceptionDescribe();
1185        env->ExceptionClear();
1186    }
1187}
1188
1189void
1190AwtDragSource::call_dSCmotion(JNIEnv* env, jobject self, jint targetActions,
1191                              jint modifiers, jint x, jint y) {
1192    DECLARE_VOID_JAVA_METHOD(dSCmotion, dSCClazz, "dragMotion", "(IIII)V");
1193    DASSERT(!JNU_IsNull(env, self));
1194    env->CallVoidMethod(self, dSCmotion, targetActions, modifiers, x, y);
1195    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
1196        env->ExceptionDescribe();
1197        env->ExceptionClear();
1198    }
1199}
1200
1201void
1202AwtDragSource::call_dSCchanged(JNIEnv* env, jobject self, jint targetActions,
1203                               jint modifiers, jint x, jint y) {
1204    DECLARE_VOID_JAVA_METHOD(dSCchanged, dSCClazz, "operationChanged",
1205                             "(IIII)V");
1206    DASSERT(!JNU_IsNull(env, self));
1207    env->CallVoidMethod(self, dSCchanged, targetActions, modifiers, x, y);
1208    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
1209        env->ExceptionDescribe();
1210        env->ExceptionClear();
1211    }
1212}
1213
1214void
1215AwtDragSource::call_dSCexit(JNIEnv* env, jobject self, jint x, jint y) {
1216    DECLARE_VOID_JAVA_METHOD(dSCexit, dSCClazz, "dragExit", "(II)V");
1217    DASSERT(!JNU_IsNull(env, self));
1218    env->CallVoidMethod(self, dSCexit, x, y);
1219    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
1220        env->ExceptionDescribe();
1221        env->ExceptionClear();
1222    }
1223}
1224
1225void
1226AwtDragSource::call_dSCddfinished(JNIEnv* env, jobject self, jboolean success,
1227                                  jint operations, jint x, jint y) {
1228    DECLARE_VOID_JAVA_METHOD(dSCddfinished, dSCClazz, "dragDropFinished", "(ZIII)V");
1229    DASSERT(!JNU_IsNull(env, self));
1230    env->CallVoidMethod(self, dSCddfinished, success, operations, x, y);
1231    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
1232        env->ExceptionDescribe();
1233        env->ExceptionClear();
1234    }
1235}
1236
1237void
1238AwtDragSource::call_dSCmouseMoved(JNIEnv* env, jobject self, jint targetActions,
1239                                  jint modifiers, jint x, jint y) {
1240    DECLARE_VOID_JAVA_METHOD(dSCmouseMoved, dSCClazz, "dragMouseMoved",
1241                             "(IIII)V");
1242    DASSERT(!JNU_IsNull(env, self));
1243    env->CallVoidMethod(self, dSCmouseMoved, targetActions, modifiers, x, y);
1244    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
1245        env->ExceptionDescribe();
1246        env->ExceptionClear();
1247    }
1248}
1249
1250DECLARE_JAVA_CLASS(awtIEClazz, "java/awt/event/InputEvent")
1251
1252/**
1253 * Constructor
1254 */
1255
1256AwtDragSource::ADSIEnumFormatEtc::ADSIEnumFormatEtc(AwtDragSource* parent) {
1257    m_parent = parent;
1258    m_idx    = 0;
1259
1260    m_refs   = 0;
1261
1262    m_parent->AddRef();
1263
1264    AddRef();
1265}
1266
1267/**
1268 * Destructor
1269 */
1270
1271AwtDragSource::ADSIEnumFormatEtc::~ADSIEnumFormatEtc() {
1272    m_parent->Release();
1273}
1274
1275/**
1276 * QueryInterface
1277 */
1278
1279HRESULT __stdcall  AwtDragSource::ADSIEnumFormatEtc::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) {
1280    TRY;
1281
1282    if (riid == IID_IUnknown) {
1283        *ppvObject = (void __RPC_FAR *__RPC_FAR)(IUnknown*)this;
1284        AddRef();
1285        return S_OK;
1286    } else if (riid == IID_IEnumFORMATETC) {
1287        *ppvObject = (void __RPC_FAR *__RPC_FAR)(IEnumFORMATETC*)this;
1288        AddRef();
1289        return S_OK;
1290    } else {
1291        *ppvObject = (void __RPC_FAR *__RPC_FAR)NULL;
1292        return E_NOINTERFACE;
1293    }
1294
1295    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1296}
1297
1298/**
1299 * AddRef
1300 */
1301
1302ULONG __stdcall  AwtDragSource::ADSIEnumFormatEtc::AddRef(void) {
1303    return (ULONG)++m_refs;
1304}
1305
1306/**
1307 * Release
1308 */
1309
1310ULONG __stdcall  AwtDragSource::ADSIEnumFormatEtc::Release(void) {
1311    int refs;
1312
1313    if ((refs = --m_refs) == 0) delete this;
1314
1315    return (ULONG)refs;
1316}
1317
1318/**
1319 * Next
1320 */
1321
1322HRESULT _stdcall AwtDragSource::ADSIEnumFormatEtc::Next(ULONG celt, FORMATETC __RPC_FAR *rgelt, ULONG __RPC_FAR *pceltFetched) {
1323    TRY;
1324
1325    unsigned int len = m_parent->getNTypes();
1326    unsigned int i;
1327
1328    for (i = 0; i < celt && m_idx < len; i++, m_idx++) {
1329        FORMATETC fetc = m_parent->getType(m_idx);
1330        rgelt[i] = fetc;
1331    }
1332
1333    if (pceltFetched != NULL) *pceltFetched = i;
1334
1335    return i == celt ? S_OK : S_FALSE;
1336
1337    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1338}
1339
1340/**
1341 * Skip
1342 */
1343
1344HRESULT __stdcall  AwtDragSource::ADSIEnumFormatEtc::Skip(ULONG celt) {
1345    TRY;
1346
1347    unsigned int len = m_parent->getNTypes();
1348    unsigned int tmp = m_idx + celt;
1349
1350    if (tmp < len) {
1351        m_idx = tmp;
1352
1353        return S_OK;
1354    } else {
1355        m_idx = len;
1356
1357        return S_FALSE;
1358    }
1359
1360    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1361}
1362
1363/**
1364 * Reset
1365 */
1366
1367HRESULT __stdcall  AwtDragSource::ADSIEnumFormatEtc::Reset(void) {
1368    m_idx = 0;
1369
1370    return S_OK;
1371}
1372
1373/**
1374 * Clone
1375 */
1376
1377HRESULT __stdcall  AwtDragSource::ADSIEnumFormatEtc::Clone(IEnumFORMATETC  __RPC_FAR *__RPC_FAR *ppenum) {
1378    TRY;
1379
1380    *ppenum = new ADSIEnumFormatEtc(m_parent);
1381    (*ppenum)->Skip(m_idx);
1382    return S_OK;
1383
1384    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1385}
1386
1387/**
1388 * constructor
1389 */
1390
1391AwtDragSource::ADSIStreamProxy::ADSIStreamProxy(AwtDragSource* parent, jbyteArray buffer, jint blen) {
1392    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1393
1394    m_parent = parent;
1395
1396    m_buffer = (signed char *)safe_Calloc(sizeof(signed char), m_blen = blen);
1397
1398    env->GetByteArrayRegion(buffer, 0, blen, m_buffer);
1399
1400    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) return;
1401
1402    m_off     = 0;
1403
1404    m_cloneof = (ADSIStreamProxy*)NULL;
1405
1406    m_refs    = 0;
1407
1408    FILETIME now;
1409
1410    ::CoFileTimeNow(&now);
1411
1412    m_statstg.pwcsName          = (LPWSTR)NULL;
1413    m_statstg.type              = STGTY_STREAM;
1414    m_statstg.cbSize.HighPart   = 0;
1415    m_statstg.cbSize.LowPart    = m_blen;
1416    m_statstg.mtime             = now;
1417    m_statstg.ctime             = now;
1418    m_statstg.atime             = now;
1419    m_statstg.grfMode           = STGM_READ;
1420    m_statstg.grfLocksSupported = FALSE;
1421    m_statstg.clsid             = CLSID_NULL;
1422    m_statstg.grfStateBits      = 0;
1423    m_statstg.reserved          = 0;
1424
1425    m_parent->AddRef();
1426
1427    AddRef();
1428}
1429
1430/**
1431 * constructor (clone)
1432 */
1433
1434AwtDragSource::ADSIStreamProxy::ADSIStreamProxy(ADSIStreamProxy* cloneof) {
1435    m_cloneof = cloneof;
1436
1437    m_parent  = cloneof->m_parent;
1438
1439    m_buffer  = cloneof->m_buffer;
1440    m_blen    = cloneof->m_blen;
1441    m_off     = cloneof->m_off;
1442
1443    m_statstg = cloneof->m_statstg;
1444
1445    m_refs    = 0;
1446
1447    m_parent->AddRef();
1448    m_cloneof->AddRef();
1449}
1450
1451/**
1452 * destructor
1453 */
1454
1455AwtDragSource::ADSIStreamProxy::~ADSIStreamProxy() {
1456    if (m_cloneof == (ADSIStreamProxy*)NULL)
1457        free((void *)m_buffer);
1458    else {
1459        m_cloneof->Release();
1460    }
1461
1462    m_parent->Release();
1463}
1464
1465/**
1466 * QueryInterface
1467 */
1468
1469HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) {
1470    TRY;
1471
1472    if (riid == IID_IUnknown) {
1473        *ppvObject = (void __RPC_FAR *__RPC_FAR)(IUnknown*)this;
1474        AddRef();
1475        return S_OK;
1476    } else if (riid == IID_IStream) {
1477        *ppvObject = (void __RPC_FAR *__RPC_FAR)(IStream*)this;
1478        AddRef();
1479        return S_OK;
1480    } else {
1481        *ppvObject = (void __RPC_FAR *__RPC_FAR)NULL;
1482        return E_NOINTERFACE;
1483    }
1484
1485    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1486}
1487
1488/**
1489 * AddRef
1490 */
1491
1492ULONG __stdcall  AwtDragSource::ADSIStreamProxy::AddRef(void) {
1493    return (ULONG)++m_refs;
1494}
1495
1496/**
1497 * Release
1498 */
1499
1500ULONG __stdcall  AwtDragSource::ADSIStreamProxy::Release(void) {
1501    int refs;
1502
1503    if ((refs = --m_refs) == 0) delete this;
1504
1505    return (ULONG)refs;
1506}
1507
1508/**
1509 * Read
1510 */
1511
1512HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead) {
1513    TRY;
1514
1515    unsigned int rem  = m_blen - m_off;
1516    int          read = cb > rem ? rem : cb;
1517
1518    if (read > 0) memmove(pv, (void *)(m_buffer + m_off), read);
1519
1520    m_off += read;
1521
1522    if (pcbRead != (ULONG __RPC_FAR *)NULL) {
1523        *pcbRead = read;
1524    }
1525
1526    FILETIME now; ::CoFileTimeNow(&now); m_statstg.atime = now;
1527
1528    return S_OK;
1529
1530    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1531}
1532
1533/**
1534 * Write
1535 */
1536
1537HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::Write(const void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbWritten) {
1538    TRY;
1539
1540    if (pcbWritten != (ULONG __RPC_FAR *)NULL) {
1541        *pcbWritten = 0;
1542    }
1543
1544    FILETIME now; ::CoFileTimeNow(&now); m_statstg.atime = now;
1545
1546    return STG_E_CANTSAVE; // don't support writing
1547
1548    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1549}
1550
1551/**
1552 * Seek
1553 */
1554
1555HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER __RPC_FAR *plibNewPosition) {
1556    TRY;
1557
1558    if (dlibMove.HighPart != 0) return STG_E_INVALIDPOINTER;
1559
1560    if (plibNewPosition != (ULARGE_INTEGER __RPC_FAR *)NULL) {
1561        plibNewPosition->HighPart = 0;
1562        plibNewPosition->LowPart  = 0;
1563    }
1564
1565    switch (dwOrigin) {
1566        case STREAM_SEEK_SET: {
1567            if (dlibMove.HighPart != 0 || dlibMove.LowPart >= m_blen) return STG_E_INVALIDPOINTER;
1568
1569            m_off = dlibMove.LowPart;
1570        }
1571        break;
1572
1573        case STREAM_SEEK_CUR:
1574        case STREAM_SEEK_END: {
1575            if (dlibMove.HighPart > 0) return STG_E_INVALIDPOINTER;
1576
1577            long newoff = (dwOrigin == STREAM_SEEK_END ? m_blen : m_off) + dlibMove.LowPart;
1578
1579            if (newoff < 0 || newoff >= (long)m_blen)
1580                return STG_E_INVALIDPOINTER;
1581            else
1582                m_off = newoff;
1583        }
1584        break;
1585
1586        default: return STG_E_INVALIDFUNCTION;
1587    }
1588
1589    if (plibNewPosition != (ULARGE_INTEGER __RPC_FAR *)NULL)
1590        plibNewPosition->LowPart = m_off;
1591
1592    FILETIME now; ::CoFileTimeNow(&now); m_statstg.atime = now;
1593
1594    return S_OK;
1595
1596    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1597}
1598
1599/**
1600 * SetSize
1601 */
1602
1603HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::SetSize(ULARGE_INTEGER libNewSize) {
1604    return STG_E_INVALIDFUNCTION;
1605}
1606
1607/**
1608 * CopyTo
1609 */
1610
1611HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::CopyTo(IStream __RPC_FAR *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER __RPC_FAR *pcbRead, ULARGE_INTEGER __RPC_FAR *pcbWritten) {
1612    TRY;
1613
1614    ULONG written = 0;
1615
1616    pcbWritten->HighPart = (ULONG)0;
1617    pcbWritten->LowPart  = (ULONG)0;
1618
1619    pcbRead->HighPart     = (ULONG)0;
1620
1621    unsigned int rem     = m_blen - m_off;
1622    int          ovrflow = cb.LowPart >= rem;
1623
1624
1625    if (cb.HighPart != 0) return STG_E_INVALIDPOINTER;
1626
1627    ULONG nbytes = pcbRead->LowPart = (ULONG)(ovrflow ? rem : cb.LowPart);
1628
1629    HRESULT res = pstm->Write((const void *)(m_buffer + m_off), nbytes, &written);
1630
1631    pcbWritten->LowPart = written;
1632
1633    FILETIME now; ::CoFileTimeNow(&now); m_statstg.atime = now;
1634
1635    return res;
1636
1637    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1638}
1639
1640/**
1641 * Commit
1642 */
1643
1644HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::Commit(DWORD grfCommitFlags) {
1645    return S_OK;
1646}
1647
1648/**
1649 * Revert
1650 */
1651
1652HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::Revert() {
1653    return S_OK;
1654}
1655
1656/**
1657 * LockRegion
1658 */
1659
1660HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
1661    return STG_E_INVALIDFUNCTION;
1662}
1663
1664/**
1665 * UnlockRegion
1666 */
1667
1668HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
1669    return STG_E_INVALIDFUNCTION;
1670}
1671
1672/**
1673 * Stat
1674 */
1675
1676HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::Stat(STATSTG __RPC_FAR *pstatstg, DWORD grfStatFlag) {
1677    TRY;
1678
1679    *pstatstg = m_statstg;
1680
1681    FILETIME now; ::CoFileTimeNow(&now); m_statstg.atime = now;
1682
1683    return S_OK;
1684
1685    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1686}
1687
1688/**
1689 * Clone
1690 */
1691
1692HRESULT __stdcall  AwtDragSource::ADSIStreamProxy::Clone(IStream __RPC_FAR *__RPC_FAR *ppstm) {
1693    TRY;
1694
1695    *ppstm = new ADSIStreamProxy(this);
1696    return S_OK;
1697
1698    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
1699}
1700
1701/*****************************************************************************/
1702
1703extern "C" {
1704
1705/**
1706 * setNativeCursor
1707 */
1708
1709JNIEXPORT void JNICALL
1710Java_sun_awt_windows_WDragSourceContextPeer_setNativeCursor(JNIEnv* env,
1711                                                            jobject self,
1712                                                            jlong nativeCtxt,
1713                                                            jobject cursor,
1714                                                            jint type) {
1715    TRY;
1716
1717    AwtDragSource* ds = (AwtDragSource*)nativeCtxt;
1718    if (ds != NULL) {
1719        ds->SetCursor(cursor);
1720    }
1721
1722    CATCH_BAD_ALLOC;
1723}
1724
1725/**
1726 * createDragSource
1727 */
1728
1729JNIEXPORT jlong JNICALL
1730Java_sun_awt_windows_WDragSourceContextPeer_createDragSource(
1731    JNIEnv* env, jobject self, jobject component, jobject transferable,
1732    jobject trigger, jint actions,
1733    jlongArray formats, jobject formatMap)
1734{
1735    TRY;
1736
1737    if (!AwtDropTarget::IsCurrentDnDDataObject(NULL)) {
1738        JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
1739                        "Drag and drop is in progress");
1740        return (jlong)NULL;
1741    }
1742
1743    AwtDragSource* ds = new AwtDragSource(env, self, component,
1744                                          transferable, trigger, actions,
1745                                          formats, formatMap);
1746
1747    DASSERT(AwtDropTarget::IsLocalDataObject(ds));
1748
1749    return (jlong)ds;
1750
1751    CATCH_BAD_ALLOC_RET(0);
1752}
1753
1754/**
1755 * doDragDrop
1756 */
1757
1758JNIEXPORT void JNICALL Java_sun_awt_windows_WDragSourceContextPeer_doDragDrop(
1759    JNIEnv* env,
1760    jobject self,
1761    jlong nativeCtxt,
1762    jobject cursor,
1763    jintArray imageData,
1764    jint imageWidth, jint imageHeight,
1765    jint x, jint y)
1766{
1767    TRY;
1768
1769    cursor = env->NewGlobalRef(cursor);
1770    if (NULL != imageData) {
1771        imageData = (jintArray)env->NewGlobalRef(imageData);
1772    }
1773
1774    AwtDragSource::StartDrag(
1775        (AwtDragSource*)nativeCtxt,
1776        cursor,
1777        imageData,
1778        imageWidth, imageHeight,
1779        x, y);
1780
1781    CATCH_BAD_ALLOC;
1782}
1783
1784} /* extern "C" */
1785