1/*
2 * Copyright (c) 1997, 2014, 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#include "awt.h"
27#include <shlwapi.h>
28#include <shellapi.h>
29#include <memory.h>
30
31#include "awt_DataTransferer.h"
32#include "awt_Toolkit.h"
33#include "java_awt_dnd_DnDConstants.h"
34#include "sun_awt_windows_WDropTargetContextPeer.h"
35#include "awt_Container.h"
36#include "alloc.h"
37#include "awt_ole.h"
38#include "awt_DnDDT.h"
39#include "awt_DnDDS.h"
40
41
42// forwards
43
44extern "C" {
45    DWORD __cdecl convertActionsToDROPEFFECT(jint actions);
46    jint  __cdecl convertDROPEFFECTToActions(DWORD effects);
47    DWORD __cdecl mapModsToDROPEFFECT(DWORD, DWORD);
48} // extern "C"
49
50
51IDataObject* AwtDropTarget::sm_pCurrentDnDDataObject = (IDataObject*)NULL;
52
53/**
54 * constructor
55 */
56
57AwtDropTarget::AwtDropTarget(JNIEnv* env, AwtComponent* component) {
58
59    m_component     = component;
60    m_window        = component->GetHWnd();
61    m_refs          = 1U;
62    m_target        = env->NewGlobalRef(component->GetTarget(env));
63    m_registered    = 0;
64    m_dataObject    = NULL;
65    m_formats       = NULL;
66    m_nformats      = 0;
67    m_dtcp          = NULL;
68    m_cfFormats     = NULL;
69    m_mutex         = ::CreateMutex(NULL, FALSE, NULL);
70    m_pIDropTargetHelper = NULL;
71}
72
73/**
74 * destructor
75 */
76
77AwtDropTarget::~AwtDropTarget() {
78    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
79
80    // fix for 6212440: on application shutdown, this object's
81    // destruction might be suppressed due to dangling COM references.
82    // On destruction, VM might be shut down already, so we should make
83    // a null check on env.
84    if (env) {
85        env->DeleteGlobalRef(m_target);
86        env->DeleteGlobalRef(m_dtcp);
87    }
88
89    ::CloseHandle(m_mutex);
90
91    UnloadCache();
92}
93
94/**
95 * QueryInterface
96 */
97
98HRESULT __stdcall AwtDropTarget::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) {
99    if ( IID_IUnknown == riid ||
100         IID_IDropTarget == riid )
101    {
102        *ppvObject = static_cast<IDropTarget*>(this);
103        AddRef();
104        return S_OK;
105    }
106    *ppvObject = NULL;
107    return E_NOINTERFACE;
108}
109
110/**
111 * AddRef
112 */
113
114ULONG __stdcall AwtDropTarget::AddRef() {
115    return (ULONG)++m_refs;
116}
117
118/**
119 * Release
120 */
121
122ULONG __stdcall AwtDropTarget::Release() {
123    int refs;
124
125    if ((refs = --m_refs) == 0) delete this;
126
127    return (ULONG)refs;
128}
129
130void ScaleDown(POINT &cp, HWND m_window) {
131    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(m_window);
132    Devices::InstanceAccess devices;
133    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
134    if (device) {
135        cp.x = device->ScaleDownX(cp.x);
136        cp.y = device->ScaleDownY(cp.y);
137    }
138}
139
140/**
141 * DragEnter
142 */
143
144HRESULT __stdcall AwtDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) {
145    TRY;
146    if (NULL != m_pIDropTargetHelper) {
147        m_pIDropTargetHelper->DragEnter(
148            m_window,
149            pDataObj,
150            (LPPOINT)&pt,
151            *pdwEffect);
152    }
153
154    AwtInterfaceLocker _lk(this);
155
156    JNIEnv*    env       = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
157    HRESULT    ret       = S_OK;
158    DWORD      retEffect = DROPEFFECT_NONE;
159    jobject    dtcp = NULL;
160
161    if ( (!IsLocalDnD() && !IsCurrentDnDDataObject(NULL)) ||
162        (IsLocalDnD()  && !IsLocalDataObject(pDataObj)))
163    {
164        *pdwEffect = retEffect;
165        return ret;
166    }
167
168    dtcp = call_dTCcreate(env);
169    if (dtcp) {
170        env->DeleteGlobalRef(m_dtcp);
171        m_dtcp = env->NewGlobalRef(dtcp);
172        env->DeleteLocalRef(dtcp);
173    }
174
175    if (JNU_IsNull(env, m_dtcp) || !JNU_IsNull(env, safe_ExceptionOccurred(env))) {
176        return ret;
177    }
178
179    LoadCache(pDataObj);
180
181    {
182        POINT cp;
183        RECT  wr;
184
185        ::GetWindowRect(m_window, &wr);
186
187        cp.x = pt.x - wr.left;
188        cp.y = pt.y - wr.top;
189        ScaleDown(cp, m_window);
190
191        jint actions = call_dTCenter(env, m_dtcp, m_target,
192                                     (jint)cp.x, (jint)cp.y,
193                                     ::convertDROPEFFECTToActions(mapModsToDROPEFFECT(*pdwEffect, grfKeyState)),
194                                     ::convertDROPEFFECTToActions(*pdwEffect),
195                                     m_cfFormats, (jlong)this);
196
197        try {
198            if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
199                env->ExceptionDescribe();
200                env->ExceptionClear();
201                actions = java_awt_dnd_DnDConstants_ACTION_NONE;
202            }
203        } catch (std::bad_alloc&) {
204            retEffect = ::convertActionsToDROPEFFECT(actions);
205            *pdwEffect = retEffect;
206            throw;
207        }
208
209        retEffect = ::convertActionsToDROPEFFECT(actions);
210    }
211
212    *pdwEffect = retEffect;
213
214    return ret;
215
216    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
217}
218
219/**
220 * DragOver
221 */
222
223HRESULT __stdcall AwtDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) {
224    TRY;
225    if (NULL != m_pIDropTargetHelper) {
226        m_pIDropTargetHelper->DragOver(
227            (LPPOINT)&pt,
228            *pdwEffect
229        );
230    }
231
232    AwtInterfaceLocker _lk(this);
233
234    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
235    HRESULT ret = S_OK;
236    POINT   cp;
237    RECT    wr;
238    jint    actions;
239
240    if ( (!IsLocalDnD() && !IsCurrentDnDDataObject(m_dataObject)) ||
241        (IsLocalDnD()  && !IsLocalDataObject(m_dataObject)))
242    {
243        *pdwEffect = DROPEFFECT_NONE;
244        return ret;
245    }
246
247    ::GetWindowRect(m_window, &wr);
248
249    cp.x = pt.x - wr.left;
250    cp.y = pt.y - wr.top;
251    ScaleDown(cp, m_window);
252
253    actions = call_dTCmotion(env, m_dtcp, m_target,(jint)cp.x, (jint)cp.y,
254                             ::convertDROPEFFECTToActions(mapModsToDROPEFFECT(*pdwEffect, grfKeyState)),
255                             ::convertDROPEFFECTToActions(*pdwEffect),
256                             m_cfFormats, (jlong)this);
257
258    try {
259        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
260            env->ExceptionDescribe();
261            env->ExceptionClear();
262            actions = java_awt_dnd_DnDConstants_ACTION_NONE;
263        }
264    } catch (std::bad_alloc&) {
265        *pdwEffect = ::convertActionsToDROPEFFECT(actions);
266        throw;
267    }
268
269    *pdwEffect = ::convertActionsToDROPEFFECT(actions);
270
271    return ret;
272
273    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
274}
275
276/**
277 * DragLeave
278 */
279
280HRESULT __stdcall AwtDropTarget::DragLeave() {
281    TRY_NO_VERIFY;
282    if (NULL != m_pIDropTargetHelper) {
283        m_pIDropTargetHelper->DragLeave();
284    }
285
286    AwtInterfaceLocker _lk(this);
287
288    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
289    HRESULT ret = S_OK;
290
291    if ( (!IsLocalDnD() && !IsCurrentDnDDataObject(m_dataObject)) ||
292        (IsLocalDnD()  && !IsLocalDataObject(m_dataObject)))
293    {
294        DragCleanup();
295        return ret;
296    }
297
298    call_dTCexit(env, m_dtcp, m_target, (jlong)this);
299
300    try {
301        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
302            env->ExceptionDescribe();
303            env->ExceptionClear();
304        }
305    } catch (std::bad_alloc&) {
306        DragCleanup();
307        throw;
308    }
309
310    DragCleanup();
311
312    return ret;
313
314    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
315}
316
317/**
318 * Drop
319 */
320
321HRESULT __stdcall AwtDropTarget::Drop(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) {
322    TRY;
323    if (NULL != m_pIDropTargetHelper) {
324        m_pIDropTargetHelper->Drop(
325            pDataObj,
326            (LPPOINT)&pt,
327            *pdwEffect
328        );
329    }
330    AwtInterfaceLocker _lk(this);
331
332    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
333    HRESULT ret = S_OK;
334    POINT   cp;
335    RECT    wr;
336
337    if ( (!IsLocalDnD() && !IsCurrentDnDDataObject(pDataObj)) ||
338        (IsLocalDnD()  && !IsLocalDataObject(pDataObj)))
339    {
340        *pdwEffect = DROPEFFECT_NONE;
341        DragCleanup();
342        return ret;
343    }
344
345    LoadCache(pDataObj);
346
347    ::GetWindowRect(m_window, &wr);
348
349    cp.x = pt.x - wr.left;
350    cp.y = pt.y - wr.top;
351    ScaleDown(cp, m_window);
352
353    m_dropActions = java_awt_dnd_DnDConstants_ACTION_NONE;
354
355    call_dTCdrop(env, m_dtcp, m_target, (jint)cp.x, (jint)cp.y,
356                 ::convertDROPEFFECTToActions(mapModsToDROPEFFECT(*pdwEffect, grfKeyState)),
357                 ::convertDROPEFFECTToActions(*pdwEffect),
358                 m_cfFormats, (jlong)this);
359
360    try {
361        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
362            env->ExceptionDescribe();
363            env->ExceptionClear();
364            ret = E_FAIL;
365        }
366    } catch (std::bad_alloc&) {
367        AwtToolkit::GetInstance().MessageLoop(AwtToolkit::SecondaryIdleFunc,
368                                              AwtToolkit::CommonPeekMessageFunc);
369        *pdwEffect = ::convertActionsToDROPEFFECT(m_dropActions);
370        DragCleanup();
371        throw;
372    }
373
374    /*
375     * Fix for 4623377.
376     * Dispatch all messages in the nested message loop running while the drop is
377     * processed. This ensures that the modal dialog shown during drop receives
378     * all events and so it is able to close. This way the app won't deadlock.
379     */
380    AwtToolkit::GetInstance().MessageLoop(AwtToolkit::SecondaryIdleFunc,
381                                          AwtToolkit::CommonPeekMessageFunc);
382
383    ret = (m_dropSuccess == JNI_TRUE) ? S_OK : E_FAIL;
384    *pdwEffect = ::convertActionsToDROPEFFECT(m_dropActions);
385
386    DragCleanup();
387
388    return ret;
389
390    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
391}
392
393/**
394 * DoDropDone
395 */
396
397void AwtDropTarget::DoDropDone(jboolean success, jint action) {
398    DropDoneRec ddr = { this, success, action };
399
400    AwtToolkit::GetInstance().InvokeFunction(_DropDone, &ddr);
401}
402
403/**
404 * _DropDone
405 */
406
407void AwtDropTarget::_DropDone(void* param) {
408    DropDonePtr ddrp = (DropDonePtr)param;
409
410    (ddrp->dropTarget)->DropDone(ddrp->success, ddrp->action);
411}
412
413/**
414 * DropDone
415 */
416
417void AwtDropTarget::DropDone(jboolean success, jint action) {
418    m_dropSuccess = success;
419    m_dropActions = action;
420    AwtToolkit::GetInstance().QuitMessageLoop(AwtToolkit::EXIT_ENCLOSING_LOOP);
421}
422
423/**
424 * DoRegisterTarget
425 */
426
427void AwtDropTarget::_RegisterTarget(void* param) {
428    RegisterTargetPtr rtrp = (RegisterTargetPtr)param;
429
430    rtrp->dropTarget->RegisterTarget(rtrp->show);
431}
432
433/**
434 * RegisterTarget
435 */
436
437void AwtDropTarget::RegisterTarget(WORD show) {
438    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
439    HRESULT res;
440
441    if (!AwtToolkit::IsMainThread()) {
442        RegisterTargetRec rtr = { this, show };
443
444        AwtToolkit::GetInstance().InvokeFunction(_RegisterTarget, &rtr);
445
446        return;
447    }
448
449    // if we are'nt yet visible, defer until the parent is!
450
451    if (show) {
452        OLE_TRY
453        OLE_HRT(CoCreateInstance(
454            CLSID_DragDropHelper,
455            NULL,
456            CLSCTX_ALL,
457            IID_IDropTargetHelper,
458            (LPVOID*)&m_pIDropTargetHelper
459        ))
460        OLE_HRT(::RegisterDragDrop(m_window, (IDropTarget*)this))
461        OLE_CATCH
462        res = OLE_HR;
463    } else {
464        res = ::RevokeDragDrop(m_window);
465        if (NULL != m_pIDropTargetHelper) {
466            m_pIDropTargetHelper->Release();
467        }
468    }
469
470    if (res == S_OK) m_registered = show;
471}
472
473/**
474 * DoGetData
475 */
476
477jobject AwtDropTarget::DoGetData(jlong format) {
478    jobject    ret = (jobject)NULL;
479    GetDataRec gdr = { this, format, &ret };
480
481    AwtToolkit::GetInstance().WaitForSingleObject(m_mutex);
482
483    AwtToolkit::GetInstance().InvokeFunctionLater(_GetData, &gdr);
484
485    WaitUntilSignalled(FALSE);
486
487    return ret;
488}
489
490/**
491 * _GetData
492 */
493
494void AwtDropTarget::_GetData(void* param) {
495    GetDataPtr gdrp = (GetDataPtr)param;
496
497    *(gdrp->ret) = gdrp->dropTarget->GetData(gdrp->format);
498
499    gdrp->dropTarget->Signal();
500}
501
502
503/**
504 * GetData
505 *
506 * Returns the data object being transferred.
507 */
508
509HRESULT AwtDropTarget::ExtractNativeData(
510    jlong fmt,
511    LONG lIndex,
512    STGMEDIUM *pmedium)
513{
514    FORMATETC format = { (unsigned short)fmt };
515    HRESULT hr = E_INVALIDARG;
516
517    static const DWORD supportedTymeds[] = {
518        TYMED_ISTREAM,
519        TYMED_ENHMF,
520        TYMED_GDI,
521        TYMED_MFPICT,
522        TYMED_FILE,
523        TYMED_HGLOBAL
524    };
525
526    for (int i = 0; i < sizeof(supportedTymeds)/sizeof(supportedTymeds[0]); ++i) {
527        // Only TYMED_HGLOBAL is supported for CF_LOCALE.
528        if (fmt == CF_LOCALE && supportedTymeds[i] != TYMED_HGLOBAL) {
529            continue;
530        }
531
532        format.tymed = supportedTymeds[i];
533        FORMATETC *cpp = (FORMATETC *)bsearch(
534            (const void *)&format,
535            (const void *)m_formats,
536            (size_t)m_nformats,
537            (size_t)sizeof(FORMATETC),
538            _compar);
539
540        if (NULL == cpp) {
541            continue;
542        }
543
544        format = *cpp;
545        format.lindex = lIndex;
546
547        hr = m_dataObject->GetData(&format, pmedium);
548        if (SUCCEEDED(hr)) {
549            return hr;
550        }
551    }
552    return hr;
553}
554
555HRESULT CheckRetValue(
556    JNIEnv* env,
557    jobject ret)
558{
559    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
560        return E_UNEXPECTED;
561    } else if (JNU_IsNull(env, ret)) {
562        return E_INVALIDARG;
563    }
564    return S_OK;
565}
566
567jobject AwtDropTarget::ConvertNativeData(JNIEnv* env, jlong fmt, STGMEDIUM *pmedium) /*throw std::bad_alloc */
568{
569    jobject ret = NULL;
570    jbyteArray paletteDataLocal = NULL;
571    HRESULT hr = S_OK;
572    switch (pmedium->tymed) {
573        case TYMED_HGLOBAL: {
574            if (fmt == CF_LOCALE) {
575                LCID *lcid = (LCID *)::GlobalLock(pmedium->hGlobal);
576                if (NULL == lcid) {
577                    hr = E_INVALIDARG;
578                } else {
579                    try{
580                        ret = AwtDataTransferer::LCIDToTextEncoding(env, *lcid);
581                        hr = CheckRetValue(env, ret);
582                    } catch (std::bad_alloc&) {
583                        hr = E_OUTOFMEMORY;
584                    }
585                    ::GlobalUnlock(pmedium->hGlobal);
586                }
587            } else {
588                ::SetLastError(0); // clear error
589                // Warning C4244.
590                // Cast SIZE_T (__int64 on 64-bit/unsigned int on 32-bit)
591                // to jsize (long).
592                SIZE_T globalSize = ::GlobalSize(pmedium->hGlobal);
593                jsize size = (globalSize <= INT_MAX) ? (jsize)globalSize : INT_MAX;
594                if (size == 0 && ::GetLastError() != 0) {
595                    hr = E_INVALIDARG;
596                } else {
597                    jbyteArray bytes = env->NewByteArray(size);
598                    if (NULL == bytes) {
599                        hr = E_OUTOFMEMORY;
600                    } else {
601                        LPVOID data = ::GlobalLock(pmedium->hGlobal);
602                        if (NULL == data) {
603                            hr = E_INVALIDARG;
604                        } else {
605                            env->SetByteArrayRegion(bytes, 0, size, (jbyte *)data);
606                            ret = bytes;
607                            //bytes is not null here => no CheckRetValue call
608                            ::GlobalUnlock(pmedium->hGlobal);
609                        }
610                    }
611                }
612            }
613            break;
614        }
615        case TYMED_FILE: {
616            jobject local = JNU_NewStringPlatform(
617                env,
618                pmedium->lpszFileName);
619            if (env->ExceptionCheck()) {
620                hr = E_OUTOFMEMORY;
621                break;
622            }
623            jstring fileName = (jstring)env->NewGlobalRef(local);
624            env->DeleteLocalRef(local);
625
626            STGMEDIUM *stgm = NULL;
627            try {
628                //on success stgm would be deallocated by JAVA call freeStgMedium
629                stgm = (STGMEDIUM *)safe_Malloc(sizeof(STGMEDIUM));
630                memcpy(stgm, pmedium, sizeof(STGMEDIUM));
631                // Warning C4311.
632                // Cast pointer to jlong (__int64).
633                ret = call_dTCgetfs(env, fileName, (jlong)stgm);
634                hr = CheckRetValue(env, ret);
635            } catch (std::bad_alloc&) {
636                hr = E_OUTOFMEMORY;
637            }
638            if (FAILED(hr)) {
639                //free just on error
640                env->DeleteGlobalRef(fileName);
641                free(stgm);
642            }
643            break;
644        }
645        case TYMED_ISTREAM: {
646            WDTCPIStreamWrapper* istream = NULL;
647            try {
648                istream = new WDTCPIStreamWrapper(pmedium);
649                // Warning C4311.
650                // Cast pointer to jlong (__int64).
651                ret = call_dTCgetis(env, (jlong)istream);
652                hr = CheckRetValue(env, ret);
653            } catch (std::bad_alloc&) {
654                hr = E_OUTOFMEMORY;
655            }
656            if (FAILED(hr) && NULL!=istream) {
657                //free just on error
658                istream->Close();
659            }
660            break;
661        }
662        case TYMED_GDI:
663            // Currently support only CF_PALETTE for TYMED_GDI.
664            if (CF_PALETTE == fmt) {
665                ret = AwtDataTransferer::GetPaletteBytes(
666                    pmedium->hBitmap,
667                    0,
668                    TRUE);
669                hr = CheckRetValue(env, ret);
670            }
671            break;
672        case TYMED_MFPICT:
673        case TYMED_ENHMF: {
674            HENHMETAFILE hEnhMetaFile = NULL;
675            if (pmedium->tymed == TYMED_MFPICT ) {
676                //let's create ENHMF from MFPICT to simplify treatment
677                LPMETAFILEPICT lpMetaFilePict =
678                    (LPMETAFILEPICT)::GlobalLock(pmedium->hMetaFilePict);
679                if (NULL == lpMetaFilePict) {
680                    hr = E_INVALIDARG;
681                } else {
682                    UINT uSize = ::GetMetaFileBitsEx(lpMetaFilePict->hMF, 0, NULL);
683                    if (0 == uSize) {
684                        hr = E_INVALIDARG;
685                    } else {
686                        try{
687                            LPBYTE lpMfBits = (LPBYTE)safe_Malloc(uSize);
688                            VERIFY(::GetMetaFileBitsEx(
689                                lpMetaFilePict->hMF,
690                                uSize,
691                                lpMfBits) == uSize);
692                            hEnhMetaFile = ::SetWinMetaFileBits(
693                                uSize,
694                                lpMfBits,
695                                NULL,
696                                lpMetaFilePict);
697                            free(lpMfBits);
698                        } catch (std::bad_alloc&) {
699                            hr = E_OUTOFMEMORY;
700                        }
701                    }
702                    ::GlobalUnlock(pmedium->hMetaFilePict);
703                }
704            } else {
705                hEnhMetaFile = pmedium->hEnhMetaFile;
706            }
707
708            if (NULL == hEnhMetaFile) {
709                hr = E_INVALIDARG;
710            } else {
711                try {
712                    paletteDataLocal = AwtDataTransferer::GetPaletteBytes(
713                        hEnhMetaFile,
714                        OBJ_ENHMETAFILE,
715                        FALSE);
716                    //paletteDataLocal can be NULL here - it is not a error!
717
718                    UINT uEmfSize = ::GetEnhMetaFileBits(hEnhMetaFile, 0, NULL);
719                    DASSERT(uEmfSize != 0);
720
721                    LPBYTE lpEmfBits = (LPBYTE)safe_Malloc(uEmfSize);
722                    //no chance to throw exception before catch => no more try-blocks
723                    //and no leaks on lpEmfBits
724
725                    VERIFY(::GetEnhMetaFileBits(
726                        hEnhMetaFile,
727                        uEmfSize,
728                        lpEmfBits) == uEmfSize);
729
730                    jbyteArray bytes = env->NewByteArray(uEmfSize);
731                    if (NULL == bytes) {
732                        hr = E_OUTOFMEMORY;
733                    } else {
734                        env->SetByteArrayRegion(bytes, 0, uEmfSize, (jbyte*)lpEmfBits);
735                        ret = bytes;
736                        //bytes is not null here => no CheckRetValue call
737                    }
738                    free(lpEmfBits);
739                } catch (std::bad_alloc&) {
740                    hr = E_OUTOFMEMORY;
741                }
742                if (pmedium->tymed == TYMED_MFPICT) {
743                    //because we create it manually
744                    ::DeleteEnhMetaFile(hEnhMetaFile);
745                }
746            }
747            break;
748        }
749        case TYMED_ISTORAGE:
750        default:
751            hr = E_NOTIMPL;
752            break;
753    }
754
755    if (FAILED(hr)) {
756        //clear exception garbage for hr = E_UNEXPECTED
757        ret  = NULL;
758    } else {
759        switch (fmt) {
760        case CF_METAFILEPICT:
761        case CF_ENHMETAFILE:
762            // If we failed to retrieve palette entries from metafile,
763            // fall through and try CF_PALETTE format.
764        case CF_DIB: {
765            if (JNU_IsNull(env, paletteDataLocal)) {
766                jobject paletteData = GetData(CF_PALETTE);
767
768                if (JNU_IsNull(env, paletteData)) {
769                    paletteDataLocal =
770                        AwtDataTransferer::GetPaletteBytes(NULL, 0, TRUE);
771                } else {
772                    // GetData() returns a global ref.
773                    // We want to deal with local ref.
774                    paletteDataLocal = (jbyteArray)env->NewLocalRef(paletteData);
775                    env->DeleteGlobalRef(paletteData);
776                }
777            }
778            DASSERT(!JNU_IsNull(env, paletteDataLocal) &&
779                    !JNU_IsNull(env, ret));
780
781            jobject concat = AwtDataTransferer::ConcatData(env, paletteDataLocal, ret);
782            env->DeleteLocalRef(ret);
783            ret = concat;
784            hr = CheckRetValue(env, ret);
785            break;
786        }
787        }
788    }
789
790    if (!JNU_IsNull(env, paletteDataLocal) ) {
791        env->DeleteLocalRef(paletteDataLocal);
792    }
793    jobject global = NULL;
794    if (SUCCEEDED(hr)) {
795        global = env->NewGlobalRef(ret);
796        env->DeleteLocalRef(ret);
797    } else if (E_UNEXPECTED == hr) {
798        //internal Java non-GPF exception
799        env->ExceptionDescribe();
800        env->ExceptionClear();
801    } else if (E_OUTOFMEMORY == hr) {
802        throw std::bad_alloc();
803    } //NULL returns for all other cases
804    return global;
805}
806
807HRESULT AwtDropTarget::SaveIndexToFile(LPCTSTR pFileName, UINT lIndex)
808{
809    OLE_TRY
810    STGMEDIUM stgmedium;
811    OLE_HRT( ExtractNativeData(CF_FILECONTENTS, lIndex, &stgmedium) );
812    OLE_NEXT_TRY
813        IStreamPtr spSrc;
814        if (TYMED_HGLOBAL == stgmedium.tymed) {
815            OLE_HRT( CreateStreamOnHGlobal(
816                stgmedium.hGlobal,
817                FALSE,
818                &spSrc
819            ));
820        } else if(TYMED_ISTREAM == stgmedium.tymed) {
821            spSrc = stgmedium.pstm;
822        }
823        if (NULL == spSrc) {
824            OLE_HRT(E_INVALIDARG);
825        }
826        IStreamPtr spDst;
827        OLE_HRT(SHCreateStreamOnFile(
828            pFileName,
829            STGM_WRITE | STGM_CREATE,
830            &spDst
831        ));
832        STATSTG si = {0};
833        OLE_HRT( spSrc->Stat(&si, STATFLAG_NONAME ) );
834        OLE_HRT( spSrc->CopyTo(spDst, si.cbSize, NULL, NULL) );
835    OLE_CATCH
836    ::ReleaseStgMedium(&stgmedium);
837    OLE_CATCH
838    OLE_RETURN_HR;
839}
840
841
842HRESULT GetTempPathWithSlash(JNIEnv *env, _bstr_t &bsTempPath) /*throws _com_error*/
843{
844    static _bstr_t _bsPath;
845
846    OLE_TRY
847    if (0 == _bsPath.length()) {
848        BOOL bSafeEmergency = TRUE;
849        TCHAR szPath[MAX_PATH*2];
850        JLClass systemCls(env, env->FindClass("java/lang/System"));
851        if (systemCls) {
852            jmethodID idGetProperty = env->GetStaticMethodID(
853                    systemCls,
854                    "getProperty",
855                    "(Ljava/lang/String;)Ljava/lang/String;");
856            if (0 != idGetProperty) {
857                static TCHAR param[] = _T("java.io.tmpdir");
858                JLString tempdir(env, JNU_NewStringPlatform(env, param));
859                if (tempdir) {
860                    JLString jsTempPath(env, (jstring)env->CallStaticObjectMethod(
861                        systemCls,
862                        idGetProperty,
863                        (jstring)tempdir
864                    ));
865                    if (jsTempPath) {
866                        _bsPath = (LPCWSTR)JavaStringBuffer(env, jsTempPath);
867                        OLE_HRT(SHGetFolderPath(
868                            NULL,
869                            CSIDL_WINDOWS,
870                            NULL,
871                            0,
872                            szPath));
873                        _tcscat(szPath, _T("\\"));
874                        //Dead environment block leads to fact that windows folder becomes temporary path.
875                        //For example while jtreg execution %TEMP%, %TMP% and etc. aren't defined.
876                        bSafeEmergency = ( 0 == _tcsicmp(_bsPath, szPath) );
877                    }
878                }
879            }
880        }
881        if (bSafeEmergency) {
882            OLE_HRT(SHGetFolderPath(
883                NULL,
884                CSIDL_INTERNET_CACHE|CSIDL_FLAG_CREATE,
885                NULL,
886                0,
887                szPath));
888            _tcscat(szPath, _T("\\"));
889            _bsPath = szPath;
890        }
891    }
892    OLE_CATCH
893    bsTempPath = _bsPath;
894    OLE_RETURN_HR
895}
896
897jobject AwtDropTarget::ConvertMemoryMappedData(JNIEnv* env, jlong fmt, STGMEDIUM *pmedium) /*throw std::bad_alloc */
898{
899    jobject retObj = NULL;
900    OLE_TRY
901    if (TYMED_HGLOBAL != pmedium->tymed) {
902        OLE_HRT(E_INVALIDARG);
903    }
904    FILEGROUPDESCRIPTORA *pfgdHead = (FILEGROUPDESCRIPTORA *)::GlobalLock(pmedium->hGlobal);
905    if (NULL == pfgdHead) {
906        OLE_HRT(E_INVALIDARG);
907    }
908    OLE_NEXT_TRY
909        if (0 == pfgdHead->cItems) {
910            OLE_HRT(E_INVALIDARG);
911        }
912        IStreamPtr spFileNames;
913        OLE_HRT( CreateStreamOnHGlobal(
914            NULL,
915            TRUE,
916            &spFileNames
917        ));
918
919        _bstr_t sbTempDir;
920        OLE_HRT( GetTempPathWithSlash(env, sbTempDir) );
921        FILEDESCRIPTORA *pfgdA = pfgdHead->fgd;
922        FILEDESCRIPTORW *pfgdW = (FILEDESCRIPTORW *)pfgdA;
923        for (UINT i = 0; i < pfgdHead->cItems; ++i) {
924            _bstr_t stFullName(sbTempDir);
925            if(CF_FILEGROUPDESCRIPTORA == fmt) {
926                stFullName += pfgdA->cFileName; //as CHAR
927                ++pfgdA;
928            } else {
929                stFullName += pfgdW->cFileName; //as WCHAR
930                ++pfgdW;
931            }
932            OLE_HRT(SaveIndexToFile(
933                stFullName,
934                i));
935            //write to stream with zero terminator
936            OLE_HRT( spFileNames->Write((LPCTSTR)stFullName, (stFullName.length() + 1)*sizeof(TCHAR), NULL) );
937        }
938        OLE_HRT( spFileNames->Write(_T(""), sizeof(TCHAR), NULL) );
939        STATSTG st;
940        OLE_HRT( spFileNames->Stat(&st, STATFLAG_NONAME) );
941
942        //empty lists was forbidden: pfgdHead->cItems > 0
943        jbyteArray bytes = env->NewByteArray(st.cbSize.LowPart);
944        if (NULL == bytes) {
945            OLE_HRT(E_OUTOFMEMORY);
946        } else {
947            HGLOBAL glob;
948            OLE_HRT(GetHGlobalFromStream(spFileNames, &glob));
949            jbyte *pFileListWithDoubleZeroTerminator = (jbyte *)::GlobalLock(glob);
950            env->SetByteArrayRegion(bytes, 0, st.cbSize.LowPart, pFileListWithDoubleZeroTerminator);
951            ::GlobalUnlock(pFileListWithDoubleZeroTerminator);
952            retObj = bytes;
953        }
954        //std::bad_alloc could happen in JStringBuffer
955        //no leaks due to wrapper
956    OLE_CATCH_BAD_ALLOC
957    ::GlobalUnlock(pmedium->hGlobal);
958    OLE_CATCH
959    jobject global = NULL;
960    if (SUCCEEDED(OLE_HR)) {
961        global = env->NewGlobalRef(retObj);
962        env->DeleteLocalRef(retObj);
963    } else if (E_OUTOFMEMORY == OLE_HR) {
964        throw std::bad_alloc();
965    }
966    return global;
967}
968
969jobject AwtDropTarget::GetData(jlong fmt)
970{
971    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
972    if (env->EnsureLocalCapacity(1) < 0) {
973        return (jobject)NULL;
974    }
975    jobject ret = NULL;
976    OLE_TRY
977    STGMEDIUM stgmedium;
978    OLE_HRT( ExtractNativeData(fmt, -1, &stgmedium) );
979    OLE_NEXT_TRY
980        if (CF_FILEGROUPDESCRIPTORA == fmt ||
981            CF_FILEGROUPDESCRIPTORW == fmt)
982        {
983            ret = ConvertMemoryMappedData(env, fmt, &stgmedium);
984        } else {
985            ret = ConvertNativeData(env, fmt, &stgmedium);
986        }
987    OLE_CATCH_BAD_ALLOC
988    ::ReleaseStgMedium(&stgmedium);
989    OLE_CATCH
990    if (E_OUTOFMEMORY == OLE_HR) {
991        throw std::bad_alloc();
992    }
993    return ret;
994}
995
996/**
997 *
998 */
999
1000int __cdecl AwtDropTarget::_compar(const void* first, const void* second) {
1001    FORMATETC *fp = (FORMATETC *)first;
1002    FORMATETC *sp = (FORMATETC *)second;
1003
1004    if (fp->cfFormat == sp->cfFormat) {
1005        return fp->tymed - sp->tymed;
1006    }
1007
1008    return fp->cfFormat - sp->cfFormat;
1009}
1010
1011const unsigned int AwtDropTarget::CACHE_INCR = 16;
1012
1013void AwtDropTarget::LoadCache(IDataObject* pDataObj) {
1014    JNIEnv*      env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1015    unsigned int cnt = 0;
1016    HRESULT      res;
1017    IEnumFORMATETC* pEnumFormatEtc = NULL;
1018
1019    if (m_dataObject != (IDataObject*)NULL) UnloadCache();
1020
1021    if (!IsLocalDnD()) {
1022        SetCurrentDnDDataObject(pDataObj);
1023    }
1024
1025    (m_dataObject = pDataObj)->AddRef();
1026
1027    res = m_dataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormatEtc);
1028
1029    if (res == S_OK) {
1030    for (;;) {
1031
1032        FORMATETC tmp;
1033        ULONG     actual = 1;
1034
1035            res = pEnumFormatEtc->Next((ULONG)1, &tmp, &actual);
1036            if (res == S_FALSE)
1037                break;
1038
1039        if (!(tmp.cfFormat  >= 1                &&
1040              tmp.ptd       == NULL             &&
1041                (tmp.lindex == -1 || CF_FILECONTENTS==tmp.cfFormat) &&
1042              tmp.dwAspect  == DVASPECT_CONTENT &&
1043                ( tmp.tymed == TYMED_HGLOBAL ||
1044               tmp.tymed    == TYMED_FILE       ||
1045               tmp.tymed    == TYMED_ISTREAM    ||
1046               tmp.tymed    == TYMED_GDI        ||
1047               tmp.tymed    == TYMED_MFPICT     ||
1048               tmp.tymed    == TYMED_ENHMF
1049              ) // but not ISTORAGE
1050             )
1051            )
1052                continue;
1053
1054        if (m_dataObject->QueryGetData(&tmp) != S_OK) continue;
1055
1056        if (m_nformats % CACHE_INCR == 0) {
1057            m_formats = (FORMATETC *)SAFE_SIZE_ARRAY_REALLOC(safe_Realloc, m_formats,
1058                                                  CACHE_INCR + m_nformats,
1059                                                  sizeof(FORMATETC));
1060        }
1061
1062        memcpy(m_formats + m_nformats, &tmp, sizeof(FORMATETC));
1063
1064        m_nformats++;
1065    }
1066
1067        // We are responsible for releasing the enumerator.
1068        pEnumFormatEtc->Release();
1069    }
1070
1071    if (m_nformats > 0) {
1072        qsort((void*)m_formats, m_nformats, sizeof(FORMATETC),
1073              AwtDropTarget::_compar);
1074    }
1075
1076    if (m_cfFormats != NULL) {
1077        env->DeleteGlobalRef(m_cfFormats);
1078    }
1079    jlongArray l_cfFormats = env->NewLongArray(m_nformats);
1080    if (l_cfFormats == NULL) {
1081        throw std::bad_alloc();
1082    }
1083    m_cfFormats = (jlongArray)env->NewGlobalRef(l_cfFormats);
1084    env->DeleteLocalRef(l_cfFormats);
1085
1086    jboolean isCopy;
1087    jlong *lcfFormats = env->GetLongArrayElements(m_cfFormats, &isCopy),
1088        *saveFormats = lcfFormats;
1089
1090    for (unsigned int i = 0; i < m_nformats; i++, lcfFormats++) {
1091        *lcfFormats = m_formats[i].cfFormat;
1092    }
1093
1094    env->ReleaseLongArrayElements(m_cfFormats, saveFormats, 0);
1095}
1096
1097/**
1098 * UnloadCache
1099 */
1100
1101void AwtDropTarget::UnloadCache() {
1102    if (m_dataObject == (IDataObject*)NULL) return;
1103
1104    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1105
1106    free((void*)m_formats);
1107    m_formats  = (FORMATETC *)NULL;
1108    m_nformats = 0;
1109
1110    // fix for 6212440: on application shutdown, this object's
1111    // destruction might be suppressed due to dangling COM references.
1112    // This method is called from the destructor.
1113    // On destruction, VM might be shut down already, so we should make
1114    // a null check on env.
1115    if (env) {
1116        env->DeleteGlobalRef(m_cfFormats);
1117    }
1118    m_cfFormats = NULL;
1119
1120    if (!IsLocalDnD()) {
1121        DASSERT(IsCurrentDnDDataObject(m_dataObject));
1122        SetCurrentDnDDataObject(NULL);
1123    }
1124
1125    m_dataObject->Release();
1126    m_dataObject = (IDataObject*)NULL;
1127}
1128
1129/**
1130 * DragCleanup
1131 */
1132
1133void AwtDropTarget::DragCleanup(void) {
1134    UnloadCache();
1135}
1136
1137BOOL AwtDropTarget::IsLocalDataObject(IDataObject __RPC_FAR *pDataObject) {
1138    BOOL local = FALSE;
1139
1140    if (pDataObject != NULL) {
1141        FORMATETC format;
1142        STGMEDIUM stgmedium;
1143
1144        format.cfFormat = AwtDragSource::PROCESS_ID_FORMAT;
1145        format.ptd      = NULL;
1146        format.dwAspect = DVASPECT_CONTENT;
1147        format.lindex   = -1;
1148        format.tymed    = TYMED_HGLOBAL;
1149
1150        if (pDataObject->GetData(&format, &stgmedium) == S_OK) {
1151            ::SetLastError(0); // clear error
1152            // Warning C4244.
1153            SIZE_T size = ::GlobalSize(stgmedium.hGlobal);
1154            if (size < sizeof(DWORD) || ::GetLastError() != 0) {
1155                ::SetLastError(0); // clear error
1156            } else {
1157
1158                DWORD id = ::CoGetCurrentProcess();
1159
1160                LPVOID data = ::GlobalLock(stgmedium.hGlobal);
1161                if (memcmp(data, &id, sizeof(id)) == 0) {
1162                    local = TRUE;
1163                }
1164                ::GlobalUnlock(stgmedium.hGlobal);
1165            }
1166            ::ReleaseStgMedium(&stgmedium);
1167        }
1168    }
1169
1170    return local;
1171}
1172
1173DECLARE_JAVA_CLASS(dTCClazz, "sun/awt/windows/WDropTargetContextPeer")
1174
1175jobject
1176AwtDropTarget::call_dTCcreate(JNIEnv* env) {
1177    DECLARE_STATIC_OBJECT_JAVA_METHOD(dTCcreate, dTCClazz,
1178                                      "getWDropTargetContextPeer",
1179                                      "()Lsun/awt/windows/WDropTargetContextPeer;");
1180    return env->CallStaticObjectMethod(clazz, dTCcreate);
1181}
1182
1183jint
1184AwtDropTarget::call_dTCenter(JNIEnv* env, jobject self, jobject component, jint x, jint y,
1185              jint dropAction, jint actions, jlongArray formats,
1186              jlong nativeCtxt) {
1187    DECLARE_JINT_JAVA_METHOD(dTCenter, dTCClazz, "handleEnterMessage",
1188                            "(Ljava/awt/Component;IIII[JJ)I");
1189    DASSERT(!JNU_IsNull(env, self));
1190    return env->CallIntMethod(self, dTCenter, component, x, y, dropAction,
1191                              actions, formats, nativeCtxt);
1192}
1193
1194void
1195AwtDropTarget::call_dTCexit(JNIEnv* env, jobject self, jobject component, jlong nativeCtxt) {
1196    DECLARE_VOID_JAVA_METHOD(dTCexit, dTCClazz, "handleExitMessage",
1197                            "(Ljava/awt/Component;J)V");
1198    DASSERT(!JNU_IsNull(env, self));
1199    env->CallVoidMethod(self, dTCexit, component, nativeCtxt);
1200}
1201
1202jint
1203AwtDropTarget::call_dTCmotion(JNIEnv* env, jobject self, jobject component, jint x, jint y,
1204               jint dropAction, jint actions, jlongArray formats,
1205               jlong nativeCtxt) {
1206    DECLARE_JINT_JAVA_METHOD(dTCmotion, dTCClazz, "handleMotionMessage",
1207                            "(Ljava/awt/Component;IIII[JJ)I");
1208    DASSERT(!JNU_IsNull(env, self));
1209    return env->CallIntMethod(self, dTCmotion, component, x, y,
1210                                 dropAction, actions, formats, nativeCtxt);
1211}
1212
1213void
1214AwtDropTarget::call_dTCdrop(JNIEnv* env, jobject self, jobject component, jint x, jint y,
1215             jint dropAction, jint actions, jlongArray formats,
1216             jlong nativeCtxt) {
1217    DECLARE_VOID_JAVA_METHOD(dTCdrop, dTCClazz, "handleDropMessage",
1218                            "(Ljava/awt/Component;IIII[JJ)V");
1219    DASSERT(!JNU_IsNull(env, self));
1220    env->CallVoidMethod(self, dTCdrop, component, x, y,
1221                           dropAction, actions, formats, nativeCtxt);
1222}
1223
1224jobject
1225AwtDropTarget::call_dTCgetfs(JNIEnv* env, jstring fileName, jlong stgmedium) {
1226    DECLARE_STATIC_OBJECT_JAVA_METHOD(dTCgetfs, dTCClazz, "getFileStream",
1227                                      "(Ljava/lang/String;J)Ljava/io/FileInputStream;");
1228    return env->CallStaticObjectMethod(clazz, dTCgetfs, fileName, stgmedium);
1229}
1230
1231jobject
1232AwtDropTarget::call_dTCgetis(JNIEnv* env, jlong istream) {
1233    DECLARE_STATIC_OBJECT_JAVA_METHOD(dTCgetis, dTCClazz, "getIStream",
1234                                      "(J)Ljava/lang/Object;");
1235    return env->CallStaticObjectMethod(clazz, dTCgetis, istream);
1236}
1237
1238/*****************************************************************************/
1239
1240/**
1241 * construct a wrapper
1242 */
1243
1244WDTCPIStreamWrapper::WDTCPIStreamWrapper(STGMEDIUM* stgmedium) {
1245    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1246
1247    m_stgmedium = *stgmedium;
1248    m_istream   = stgmedium->pstm;
1249    m_istream->AddRef();
1250    m_mutex     = ::CreateMutex(NULL, FALSE, NULL);
1251}
1252
1253/**
1254 * destroy a wrapper
1255 */
1256
1257WDTCPIStreamWrapper::~WDTCPIStreamWrapper() {
1258    ::CloseHandle(m_mutex);
1259    m_istream->Release();
1260    ::ReleaseStgMedium(&m_stgmedium);
1261}
1262
1263/**
1264 * return available data
1265 */
1266
1267jint WDTCPIStreamWrapper::DoAvailable(WDTCPIStreamWrapper* istream) {
1268    WDTCPIStreamWrapperRec iswr = { istream, 0 };
1269
1270    AwtToolkit::GetInstance().WaitForSingleObject(istream->m_mutex);
1271
1272    AwtToolkit::GetInstance().InvokeFunctionLater( _Available, &iswr);
1273
1274    istream->WaitUntilSignalled(FALSE);
1275
1276    return iswr.ret;
1277}
1278
1279/**
1280 * return available data
1281 */
1282
1283void WDTCPIStreamWrapper::_Available(void *param) {
1284    WDTCPIStreamWrapperPtr iswrp = (WDTCPIStreamWrapperPtr)param;
1285
1286    iswrp->ret = (iswrp->istream)->Available();
1287
1288    iswrp->istream->Signal();
1289}
1290
1291/**
1292 * return available data
1293 */
1294
1295jint WDTCPIStreamWrapper::Available() {
1296    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1297
1298    if (m_istream->Stat(&m_statstg, STATFLAG_NONAME) != S_OK) {
1299        JNU_ThrowIOException(env, "IStream::Stat() failed");
1300        return 0;
1301    }
1302
1303    if (m_statstg.cbSize.QuadPart > 0x7ffffffL) {
1304        JNU_ThrowIOException(env, "IStream::Stat() cbSize > 0x7ffffff");
1305        return 0;
1306    }
1307
1308    return (jint)m_statstg.cbSize.LowPart;
1309}
1310
1311/**
1312 * read 1 byte
1313 */
1314
1315jint WDTCPIStreamWrapper::DoRead(WDTCPIStreamWrapper* istream) {
1316    WDTCPIStreamWrapperRec iswr = { istream, 0 };
1317
1318    AwtToolkit::GetInstance().WaitForSingleObject(istream->m_mutex);
1319
1320    AwtToolkit::GetInstance().InvokeFunctionLater(_Read, &iswr);
1321
1322    istream->WaitUntilSignalled(FALSE);
1323
1324    return iswr.ret;
1325}
1326
1327/**
1328 * read 1 byte
1329 */
1330
1331void WDTCPIStreamWrapper::_Read(void* param) {
1332    WDTCPIStreamWrapperPtr iswrp = (WDTCPIStreamWrapperPtr)param;
1333
1334    iswrp->ret = (iswrp->istream)->Read();
1335
1336    iswrp->istream->Signal();
1337}
1338
1339/**
1340 * read 1 byte
1341 */
1342
1343jint WDTCPIStreamWrapper::Read() {
1344    JNIEnv* env    = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1345    jint    b      = 0;
1346    ULONG   actual = 0;
1347    HRESULT res;
1348
1349    switch (res = m_istream->Read((void *)&b, (ULONG)1, &actual)) {
1350        case S_FALSE:
1351            return (jint)-1;
1352
1353        case S_OK:
1354            return (jint)(actual == 0 ? -1 : b);
1355
1356        default:
1357            JNU_ThrowIOException(env, "IStream::Read failed");
1358    }
1359    return (jint)-1;
1360}
1361
1362/**
1363 * read Buffer
1364 */
1365
1366jint WDTCPIStreamWrapper::DoReadBytes(WDTCPIStreamWrapper* istream, jbyteArray array, jint off, jint len) {
1367    WDTCPIStreamWrapperReadBytesRec iswrbr = { istream, 0, array, off, len };
1368
1369    AwtToolkit::GetInstance().WaitForSingleObject(istream->m_mutex);
1370
1371    AwtToolkit::GetInstance().InvokeFunctionLater(_ReadBytes, &iswrbr);
1372
1373    istream->WaitUntilSignalled(FALSE);
1374
1375    return iswrbr.ret;
1376}
1377
1378/**
1379 * read buffer
1380 */
1381
1382void WDTCPIStreamWrapper::_ReadBytes(void*  param) {
1383    WDTCPIStreamWrapperReadBytesPtr iswrbrp =
1384        (WDTCPIStreamWrapperReadBytesPtr)param;
1385
1386    iswrbrp->ret = (iswrbrp->istream)->ReadBytes(iswrbrp->array,
1387                                                 iswrbrp->off,
1388                                                 iswrbrp->len);
1389    iswrbrp->istream->Signal();
1390}
1391
1392/**
1393 * read buffer
1394 */
1395
1396jint WDTCPIStreamWrapper::ReadBytes(jbyteArray buf, jint off, jint len) {
1397    JNIEnv*  env     = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1398    jboolean isCopy  = JNI_FALSE;
1399    ULONG    actual  = 0;
1400    jbyte*   local   = env->GetByteArrayElements(buf, &isCopy);
1401    HRESULT  res;
1402    CHECK_NULL_RETURN(local, (jint)-1);
1403
1404    switch (res = m_istream->Read((void *)(local + off), (ULONG)len, &actual)) {
1405        case S_FALSE:
1406        case S_OK: {
1407            int eof = (actual == 0);
1408
1409            env->ReleaseByteArrayElements(buf, local, !eof ? 0 : JNI_ABORT);
1410            return (jint)(!eof ? actual : -1);
1411        }
1412
1413        default:
1414            env->ReleaseByteArrayElements(buf, local, JNI_ABORT);
1415            JNU_ThrowIOException(env, "IStream::Read failed");
1416    }
1417
1418    return (jint)-1;
1419}
1420
1421/**
1422 * close
1423 */
1424
1425void WDTCPIStreamWrapper::DoClose(WDTCPIStreamWrapper* istream) {
1426    AwtToolkit::GetInstance().InvokeFunctionLater(_Close, istream);
1427}
1428
1429/**
1430 * close
1431 */
1432
1433void WDTCPIStreamWrapper::_Close(void* param) {
1434    ((WDTCPIStreamWrapper*)param)->Close();
1435}
1436
1437/**
1438 * close
1439 */
1440
1441void WDTCPIStreamWrapper::Close() {
1442    delete this;
1443}
1444
1445/*****************************************************************************/
1446
1447extern "C" {
1448
1449/**
1450 * awt_dnd_initialize: initial DnD system
1451 */
1452
1453void awt_dnd_initialize() {
1454    ::OleInitialize((LPVOID)NULL);
1455}
1456
1457/**
1458 * awt_dnd_uninitialize: deactivate DnD system
1459 */
1460
1461void awt_dnd_uninitialize() {
1462    ::OleUninitialize();
1463}
1464
1465/**
1466 * convertActionsToDROPEFFECT
1467 */
1468
1469DWORD convertActionsToDROPEFFECT(jint actions) {
1470    DWORD effects = DROPEFFECT_NONE;
1471
1472    if (actions & java_awt_dnd_DnDConstants_ACTION_LINK) effects |= DROPEFFECT_LINK;
1473    if (actions & java_awt_dnd_DnDConstants_ACTION_MOVE) effects |= DROPEFFECT_MOVE;
1474    if (actions & java_awt_dnd_DnDConstants_ACTION_COPY) effects |= DROPEFFECT_COPY;
1475    return effects;
1476}
1477
1478/**
1479 * convertDROPEFFECTToAction
1480 */
1481
1482jint convertDROPEFFECTToActions(DWORD effects) {
1483    jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
1484
1485    if (effects & DROPEFFECT_LINK) actions |= java_awt_dnd_DnDConstants_ACTION_LINK;
1486    if (effects & DROPEFFECT_MOVE) actions |= java_awt_dnd_DnDConstants_ACTION_MOVE;
1487    if (effects & DROPEFFECT_COPY) actions |= java_awt_dnd_DnDConstants_ACTION_COPY;
1488
1489    return actions;
1490}
1491
1492/**
1493 * map keyboard modifiers to a DROPEFFECT
1494 */
1495
1496DWORD mapModsToDROPEFFECT(DWORD effects, DWORD mods) {
1497    DWORD ret = DROPEFFECT_NONE;
1498
1499    /*
1500     * Fix for 4285634.
1501     * Calculate the drop action to match Motif DnD behavior.
1502     * If the user selects an operation (by pressing a modifier key),
1503     * return the selected operation or DROPEFFECT_NONE if the selected
1504     * operation is not supported by the drag source.
1505     * If the user doesn't select an operation search the set of operations
1506     * supported by the drag source for DROPEFFECT_MOVE, then for
1507     * DROPEFFECT_COPY, then for DROPEFFECT_LINK and return the first operation
1508     * found.
1509     */
1510    switch (mods & (MK_CONTROL | MK_SHIFT)) {
1511        case MK_CONTROL:
1512            ret = DROPEFFECT_COPY;
1513        break;
1514
1515        case MK_CONTROL | MK_SHIFT:
1516            ret = DROPEFFECT_LINK;
1517        break;
1518
1519        case MK_SHIFT:
1520            ret = DROPEFFECT_MOVE;
1521        break;
1522
1523        default:
1524            if (effects & DROPEFFECT_MOVE) {
1525                ret = DROPEFFECT_MOVE;
1526            } else if (effects & DROPEFFECT_COPY) {
1527                ret = DROPEFFECT_COPY;
1528            } else if (effects & DROPEFFECT_LINK) {
1529                ret = DROPEFFECT_LINK;
1530            }
1531            break;
1532    }
1533
1534    return ret & effects;
1535}
1536
1537/**
1538 * downcall to fetch data ... gets scheduled on message thread
1539 */
1540
1541JNIEXPORT jobject JNICALL Java_sun_awt_windows_WDropTargetContextPeer_getData(JNIEnv* env, jobject self, jlong dropTarget, jlong format) {
1542    TRY;
1543
1544    AwtDropTarget* pDropTarget = (AwtDropTarget*)dropTarget;
1545
1546    DASSERT(!::IsBadReadPtr(pDropTarget, sizeof(AwtDropTarget)));
1547    return pDropTarget->DoGetData(format);
1548
1549    CATCH_BAD_ALLOC_RET(NULL);
1550}
1551
1552/**
1553 * downcall to signal drop done ... gets scheduled on message thread
1554 */
1555
1556JNIEXPORT void JNICALL
1557Java_sun_awt_windows_WDropTargetContextPeer_dropDone(JNIEnv* env, jobject self,
1558                             jlong dropTarget, jboolean success, jint actions) {
1559    TRY_NO_HANG;
1560
1561    AwtDropTarget* pDropTarget = (AwtDropTarget*)dropTarget;
1562
1563    DASSERT(!::IsBadReadPtr(pDropTarget, sizeof(AwtDropTarget)));
1564    pDropTarget->DoDropDone(success, actions);
1565
1566    CATCH_BAD_ALLOC;
1567}
1568
1569/**
1570 * downcall to free up storage medium for FileStream
1571 */
1572
1573JNIEXPORT void JNICALL Java_sun_awt_windows_WDropTargetContextPeerFileStream_freeStgMedium(JNIEnv* env, jobject self, jlong stgmedium) {
1574    TRY;
1575
1576    ::ReleaseStgMedium((STGMEDIUM*)stgmedium);
1577
1578    free((void*)stgmedium);
1579
1580    CATCH_BAD_ALLOC;
1581}
1582
1583/**
1584 *
1585 */
1586
1587JNIEXPORT jint JNICALL Java_sun_awt_windows_WDropTargetContextPeerIStream_Available(JNIEnv* env, jobject self, jlong istream) {
1588    TRY;
1589
1590    return WDTCPIStreamWrapper::DoAvailable((WDTCPIStreamWrapper*)istream);
1591
1592    CATCH_BAD_ALLOC_RET(0);
1593}
1594
1595/**
1596 *
1597 */
1598
1599JNIEXPORT jint JNICALL Java_sun_awt_windows_WDropTargetContextPeerIStream_Read(JNIEnv* env, jobject self, jlong istream) {
1600    TRY;
1601
1602    return WDTCPIStreamWrapper::DoRead((WDTCPIStreamWrapper*)istream);
1603
1604    CATCH_BAD_ALLOC_RET(0);
1605}
1606
1607/**
1608 *
1609 */
1610
1611JNIEXPORT jint JNICALL Java_sun_awt_windows_WDropTargetContextPeerIStream_ReadBytes(JNIEnv* env, jobject self, jlong istream, jbyteArray buf, jint off, jint len) {
1612    TRY;
1613
1614    return WDTCPIStreamWrapper::DoReadBytes((WDTCPIStreamWrapper*)istream, buf, off, len);
1615
1616    CATCH_BAD_ALLOC_RET(0);
1617}
1618
1619/**
1620 *
1621 */
1622
1623JNIEXPORT void JNICALL Java_sun_awt_windows_WDropTargetContextPeerIStream_Close(JNIEnv* env, jobject self, jlong istream) {
1624    TRY_NO_VERIFY;
1625
1626    WDTCPIStreamWrapper::DoClose((WDTCPIStreamWrapper*)istream);
1627
1628    CATCH_BAD_ALLOC;
1629}
1630
1631} /* extern "C" */
1632