alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (awt_DnDDT.cpp)

This example Java source code file (awt_DnDDT.cpp) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

dassert, dword, e_outofmemory, formatetc, hresult, islocaldnd, jni_version_1_2, jnienv, jnu_getenv, jnu_isnull, null, ole_hrt, s_ok, ulong

The awt_DnDDT.cpp Java example source code

/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#include "awt.h"
#include <shlwapi.h>
#include <shellapi.h>
#include <memory.h>

#include "awt_DataTransferer.h"
#include "awt_Toolkit.h"
#include "java_awt_dnd_DnDConstants.h"
#include "sun_awt_windows_WDropTargetContextPeer.h"
#include "awt_Container.h"
#include "alloc.h"
#include "awt_ole.h"
#include "awt_DnDDT.h"
#include "awt_DnDDS.h"


// forwards

extern "C" {
    DWORD __cdecl convertActionsToDROPEFFECT(jint actions);
    jint  __cdecl convertDROPEFFECTToActions(DWORD effects);
    DWORD __cdecl mapModsToDROPEFFECT(DWORD, DWORD);
} // extern "C"


IDataObject* AwtDropTarget::sm_pCurrentDnDDataObject = (IDataObject*)NULL;

/**
 * constructor
 */

AwtDropTarget::AwtDropTarget(JNIEnv* env, AwtComponent* component) {

    m_component     = component;
    m_window        = component->GetHWnd();
    m_refs          = 1U;
    m_target        = env->NewGlobalRef(component->GetTarget(env));
    m_registered    = 0;
    m_dataObject    = NULL;
    m_formats       = NULL;
    m_nformats      = 0;
    m_dtcp          = NULL;
    m_cfFormats     = NULL;
    m_mutex         = ::CreateMutex(NULL, FALSE, NULL);
    m_pIDropTargetHelper = NULL;
}

/**
 * destructor
 */

AwtDropTarget::~AwtDropTarget() {
    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    // fix for 6212440: on application shutdown, this object's
    // destruction might be suppressed due to dangling COM references.
    // On destruction, VM might be shut down already, so we should make
    // a null check on env.
    if (env) {
        env->DeleteGlobalRef(m_target);
        env->DeleteGlobalRef(m_dtcp);
    }

    ::CloseHandle(m_mutex);

    UnloadCache();
}

/**
 * QueryInterface
 */

HRESULT __stdcall AwtDropTarget::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) {
    if ( IID_IUnknown == riid ||
         IID_IDropTarget == riid )
    {
        *ppvObject = static_cast<IDropTarget*>(this);
        AddRef();
        return S_OK;
    }
    *ppvObject = NULL;
    return E_NOINTERFACE;
}

/**
 * AddRef
 */

ULONG __stdcall AwtDropTarget::AddRef() {
    return (ULONG)++m_refs;
}

/**
 * Release
 */

ULONG __stdcall AwtDropTarget::Release() {
    int refs;

    if ((refs = --m_refs) == 0) delete this;

    return (ULONG)refs;
}

/**
 * DragEnter
 */

HRESULT __stdcall AwtDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) {
    TRY;
    if (NULL != m_pIDropTargetHelper) {
        m_pIDropTargetHelper->DragEnter(
            m_window,
            pDataObj,
            (LPPOINT)&pt,
            *pdwEffect);
    }

    AwtInterfaceLocker _lk(this);

    JNIEnv*    env       = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    HRESULT    ret       = S_OK;
    DWORD      retEffect = DROPEFFECT_NONE;
    jobject    dtcp = NULL;

    if ( (!IsLocalDnD() && !IsCurrentDnDDataObject(NULL)) ||
        (IsLocalDnD()  && !IsLocalDataObject(pDataObj)))
    {
        *pdwEffect = retEffect;
        return ret;
    }

    dtcp = call_dTCcreate(env);
    if (dtcp) {
        env->DeleteGlobalRef(m_dtcp);
        m_dtcp = env->NewGlobalRef(dtcp);
        env->DeleteLocalRef(dtcp);
    }

    if (JNU_IsNull(env, m_dtcp) || !JNU_IsNull(env, safe_ExceptionOccurred(env))) {
        return ret;
    }

    LoadCache(pDataObj);

    {
        POINT cp;
        RECT  wr;

        ::GetWindowRect(m_window, &wr);

        cp.x = pt.x - wr.left;
        cp.y = pt.y - wr.top;

        jint actions = call_dTCenter(env, m_dtcp, m_target,
                                     (jint)cp.x, (jint)cp.y,
                                     ::convertDROPEFFECTToActions(mapModsToDROPEFFECT(*pdwEffect, grfKeyState)),
                                     ::convertDROPEFFECTToActions(*pdwEffect),
                                     m_cfFormats, (jlong)this);

        try {
            if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
                env->ExceptionDescribe();
                env->ExceptionClear();
                actions = java_awt_dnd_DnDConstants_ACTION_NONE;
            }
        } catch (std::bad_alloc&) {
            retEffect = ::convertActionsToDROPEFFECT(actions);
            *pdwEffect = retEffect;
            throw;
        }

        retEffect = ::convertActionsToDROPEFFECT(actions);
    }

    *pdwEffect = retEffect;

    return ret;

    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
}

/**
 * DragOver
 */

HRESULT __stdcall AwtDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) {
    TRY;
    if (NULL != m_pIDropTargetHelper) {
        m_pIDropTargetHelper->DragOver(
            (LPPOINT)&pt,
            *pdwEffect
        );
    }

    AwtInterfaceLocker _lk(this);

    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    HRESULT ret = S_OK;
    POINT   cp;
    RECT    wr;
    jint    actions;

    if ( (!IsLocalDnD() && !IsCurrentDnDDataObject(m_dataObject)) ||
        (IsLocalDnD()  && !IsLocalDataObject(m_dataObject)))
    {
        *pdwEffect = DROPEFFECT_NONE;
        return ret;
    }

    ::GetWindowRect(m_window, &wr);

    cp.x = pt.x - wr.left;
    cp.y = pt.y - wr.top;

    actions = call_dTCmotion(env, m_dtcp, m_target,(jint)cp.x, (jint)cp.y,
                             ::convertDROPEFFECTToActions(mapModsToDROPEFFECT(*pdwEffect, grfKeyState)),
                             ::convertDROPEFFECTToActions(*pdwEffect),
                             m_cfFormats, (jlong)this);

    try {
        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
            env->ExceptionDescribe();
            env->ExceptionClear();
            actions = java_awt_dnd_DnDConstants_ACTION_NONE;
        }
    } catch (std::bad_alloc&) {
        *pdwEffect = ::convertActionsToDROPEFFECT(actions);
        throw;
    }

    *pdwEffect = ::convertActionsToDROPEFFECT(actions);

    return ret;

    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
}

/**
 * DragLeave
 */

HRESULT __stdcall AwtDropTarget::DragLeave() {
    TRY_NO_VERIFY;
    if (NULL != m_pIDropTargetHelper) {
        m_pIDropTargetHelper->DragLeave();
    }

    AwtInterfaceLocker _lk(this);

    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    HRESULT ret = S_OK;

    if ( (!IsLocalDnD() && !IsCurrentDnDDataObject(m_dataObject)) ||
        (IsLocalDnD()  && !IsLocalDataObject(m_dataObject)))
    {
        DragCleanup();
        return ret;
    }

    call_dTCexit(env, m_dtcp, m_target, (jlong)this);

    try {
        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
            env->ExceptionDescribe();
            env->ExceptionClear();
        }
    } catch (std::bad_alloc&) {
        DragCleanup();
        throw;
    }

    DragCleanup();

    return ret;

    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
}

/**
 * Drop
 */

HRESULT __stdcall AwtDropTarget::Drop(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) {
    TRY;
    if (NULL != m_pIDropTargetHelper) {
        m_pIDropTargetHelper->Drop(
            pDataObj,
            (LPPOINT)&pt,
            *pdwEffect
        );
    }
    AwtInterfaceLocker _lk(this);

    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    HRESULT ret = S_OK;
    POINT   cp;
    RECT    wr;

    if ( (!IsLocalDnD() && !IsCurrentDnDDataObject(pDataObj)) ||
        (IsLocalDnD()  && !IsLocalDataObject(pDataObj)))
    {
        *pdwEffect = DROPEFFECT_NONE;
        DragCleanup();
        return ret;
    }

    LoadCache(pDataObj);

    ::GetWindowRect(m_window, &wr);

    cp.x = pt.x - wr.left;
    cp.y = pt.y - wr.top;

    m_dropActions = java_awt_dnd_DnDConstants_ACTION_NONE;

    call_dTCdrop(env, m_dtcp, m_target, (jint)cp.x, (jint)cp.y,
                 ::convertDROPEFFECTToActions(mapModsToDROPEFFECT(*pdwEffect, grfKeyState)),
                 ::convertDROPEFFECTToActions(*pdwEffect),
                 m_cfFormats, (jlong)this);

    try {
        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
            env->ExceptionDescribe();
            env->ExceptionClear();
            ret = E_FAIL;
        }
    } catch (std::bad_alloc&) {
        AwtToolkit::GetInstance().MessageLoop(AwtToolkit::SecondaryIdleFunc,
                                              AwtToolkit::CommonPeekMessageFunc);
        *pdwEffect = ::convertActionsToDROPEFFECT(m_dropActions);
        DragCleanup();
        throw;
    }

    /*
     * Fix for 4623377.
     * Dispatch all messages in the nested message loop running while the drop is
     * processed. This ensures that the modal dialog shown during drop receives
     * all events and so it is able to close. This way the app won't deadlock.
     */
    AwtToolkit::GetInstance().MessageLoop(AwtToolkit::SecondaryIdleFunc,
                                          AwtToolkit::CommonPeekMessageFunc);

    ret = (m_dropSuccess == JNI_TRUE) ? S_OK : E_FAIL;
    *pdwEffect = ::convertActionsToDROPEFFECT(m_dropActions);

    DragCleanup();

    return ret;

    CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY);
}

/**
 * DoDropDone
 */

void AwtDropTarget::DoDropDone(jboolean success, jint action) {
    DropDoneRec ddr = { this, success, action };

    AwtToolkit::GetInstance().InvokeFunction(_DropDone, &ddr);
}

/**
 * _DropDone
 */

void AwtDropTarget::_DropDone(void* param) {
    DropDonePtr ddrp = (DropDonePtr)param;

    (ddrp->dropTarget)->DropDone(ddrp->success, ddrp->action);
}

/**
 * DropDone
 */

void AwtDropTarget::DropDone(jboolean success, jint action) {
    m_dropSuccess = success;
    m_dropActions = action;
    AwtToolkit::GetInstance().QuitMessageLoop(AwtToolkit::EXIT_ENCLOSING_LOOP);
}

/**
 * DoRegisterTarget
 */

void AwtDropTarget::_RegisterTarget(void* param) {
    RegisterTargetPtr rtrp = (RegisterTargetPtr)param;

    rtrp->dropTarget->RegisterTarget(rtrp->show);
}

/**
 * RegisterTarget
 */

void AwtDropTarget::RegisterTarget(WORD show) {
    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    HRESULT res;

    if (!AwtToolkit::IsMainThread()) {
        RegisterTargetRec rtr = { this, show };

        AwtToolkit::GetInstance().InvokeFunction(_RegisterTarget, &rtr);

        return;
    }

    // if we are'nt yet visible, defer until the parent is!

    if (show) {
        OLE_TRY
        OLE_HRT(CoCreateInstance(
            CLSID_DragDropHelper,
            NULL,
            CLSCTX_ALL,
            IID_IDropTargetHelper,
            (LPVOID*)&m_pIDropTargetHelper
        ))
        OLE_HRT(::RegisterDragDrop(m_window, (IDropTarget*)this))
        OLE_CATCH
        res = OLE_HR;
    } else {
        res = ::RevokeDragDrop(m_window);
        if (NULL != m_pIDropTargetHelper) {
            m_pIDropTargetHelper->Release();
        }
    }

    if (res == S_OK) m_registered = show;
}

/**
 * DoGetData
 */

jobject AwtDropTarget::DoGetData(jlong format) {
    jobject    ret = (jobject)NULL;
    GetDataRec gdr = { this, format, &ret };

    AwtToolkit::GetInstance().WaitForSingleObject(m_mutex);

    AwtToolkit::GetInstance().InvokeFunctionLater(_GetData, &gdr);

    WaitUntilSignalled(FALSE);

    return ret;
}

/**
 * _GetData
 */

void AwtDropTarget::_GetData(void* param) {
    GetDataPtr gdrp = (GetDataPtr)param;

    *(gdrp->ret) = gdrp->dropTarget->GetData(gdrp->format);

    gdrp->dropTarget->Signal();
}


/**
 * GetData
 *
 * Returns the data object being transferred.
 */

HRESULT AwtDropTarget::ExtractNativeData(
    jlong fmt,
    LONG lIndex,
    STGMEDIUM *pmedium)
{
    FORMATETC format = { (unsigned short)fmt };
    HRESULT hr = E_INVALIDARG;

    static const DWORD supportedTymeds[] = {
        TYMED_ISTREAM,
        TYMED_ENHMF,
        TYMED_GDI,
        TYMED_MFPICT,
        TYMED_FILE,
        TYMED_HGLOBAL
    };

    for (int i = 0; i < sizeof(supportedTymeds)/sizeof(supportedTymeds[0]); ++i) {
        // Only TYMED_HGLOBAL is supported for CF_LOCALE.
        if (fmt == CF_LOCALE && supportedTymeds[i] != TYMED_HGLOBAL) {
            continue;
        }

        format.tymed = supportedTymeds[i];
        FORMATETC *cpp = (FORMATETC *)bsearch(
            (const void *)&format,
            (const void *)m_formats,
            (size_t)m_nformats,
            (size_t)sizeof(FORMATETC),
            _compar);

        if (NULL == cpp) {
            continue;
        }

        format = *cpp;
        format.lindex = lIndex;

        hr = m_dataObject->GetData(&format, pmedium);
        if (SUCCEEDED(hr)) {
            return hr;
        }
    }
    return hr;
}

HRESULT CheckRetValue(
    JNIEnv* env,
    jobject ret)
{
    if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
        return E_UNEXPECTED;
    } else if (JNU_IsNull(env, ret)) {
        return E_INVALIDARG;
    }
    return S_OK;
}

jobject AwtDropTarget::ConvertNativeData(JNIEnv* env, jlong fmt, STGMEDIUM *pmedium) /*throw std::bad_alloc */
{
    jobject ret = NULL;
    jbyteArray paletteDataLocal = NULL;
    HRESULT hr = S_OK;
    switch (pmedium->tymed) {
        case TYMED_HGLOBAL: {
            if (fmt == CF_LOCALE) {
                LCID *lcid = (LCID *)::GlobalLock(pmedium->hGlobal);
                if (NULL == lcid) {
                    hr = E_INVALIDARG;
                } else {
                    try{
                        ret = AwtDataTransferer::LCIDToTextEncoding(env, *lcid);
                        hr = CheckRetValue(env, ret);
                    } catch (std::bad_alloc&) {
                        hr = E_OUTOFMEMORY;
                    }
                    ::GlobalUnlock(pmedium->hGlobal);
                }
            } else {
                ::SetLastError(0); // clear error
                // Warning C4244.
                // Cast SIZE_T (__int64 on 64-bit/unsigned int on 32-bit)
                // to jsize (long).
                SIZE_T globalSize = ::GlobalSize(pmedium->hGlobal);
                jsize size = (globalSize <= INT_MAX) ? (jsize)globalSize : INT_MAX;
                if (size == 0 && ::GetLastError() != 0) {
                    hr = E_INVALIDARG;
                } else {
                    jbyteArray bytes = env->NewByteArray(size);
                    if (NULL == bytes) {
                        hr = E_OUTOFMEMORY;
                    } else {
                        LPVOID data = ::GlobalLock(pmedium->hGlobal);
                        if (NULL == data) {
                            hr = E_INVALIDARG;
                        } else {
                            env->SetByteArrayRegion(bytes, 0, size, (jbyte *)data);
                            ret = bytes;
                            //bytes is not null here => no CheckRetValue call
                            ::GlobalUnlock(pmedium->hGlobal);
                        }
                    }
                }
            }
            break;
        }
        case TYMED_FILE: {
            jobject local = JNU_NewStringPlatform(
                env,
                pmedium->lpszFileName);
            jstring fileName = (jstring)env->NewGlobalRef(local);
            env->DeleteLocalRef(local);

            STGMEDIUM *stgm = NULL;
            try {
                //on success stgm would be deallocated by JAVA call freeStgMedium
                stgm = (STGMEDIUM *)safe_Malloc(sizeof(STGMEDIUM));
                memcpy(stgm, pmedium, sizeof(STGMEDIUM));
                // Warning C4311.
                // Cast pointer to jlong (__int64).
                ret = call_dTCgetfs(env, fileName, (jlong)stgm);
                hr = CheckRetValue(env, ret);
            } catch (std::bad_alloc&) {
                hr = E_OUTOFMEMORY;
            }
            if (FAILED(hr)) {
                //free just on error
                env->DeleteGlobalRef(fileName);
                free(stgm);
            }
            break;
        }
        case TYMED_ISTREAM: {
            WDTCPIStreamWrapper* istream = NULL;
            try {
                istream = new WDTCPIStreamWrapper(pmedium);
                // Warning C4311.
                // Cast pointer to jlong (__int64).
                ret = call_dTCgetis(env, (jlong)istream);
                hr = CheckRetValue(env, ret);
            } catch (std::bad_alloc&) {
                hr = E_OUTOFMEMORY;
            }
            if (FAILED(hr) && NULL!=istream) {
                //free just on error
                istream->Close();
            }
            break;
        }
        case TYMED_GDI:
            // Currently support only CF_PALETTE for TYMED_GDI.
            if (CF_PALETTE == fmt) {
                ret = AwtDataTransferer::GetPaletteBytes(
                    pmedium->hBitmap,
                    0,
                    TRUE);
                hr = CheckRetValue(env, ret);
            }
            break;
        case TYMED_MFPICT:
        case TYMED_ENHMF: {
            HENHMETAFILE hEnhMetaFile = NULL;
            if (pmedium->tymed == TYMED_MFPICT ) {
                //let's create ENHMF from MFPICT to simplify treatment
                LPMETAFILEPICT lpMetaFilePict =
                    (LPMETAFILEPICT)::GlobalLock(pmedium->hMetaFilePict);
                if (NULL == lpMetaFilePict) {
                    hr = E_INVALIDARG;
                } else {
                    UINT uSize = ::GetMetaFileBitsEx(lpMetaFilePict->hMF, 0, NULL);
                    if (0 == uSize) {
                        hr = E_INVALIDARG;
                    } else {
                        try{
                            LPBYTE lpMfBits = (LPBYTE)safe_Malloc(uSize);
                            VERIFY(::GetMetaFileBitsEx(
                                lpMetaFilePict->hMF,
                                uSize,
                                lpMfBits) == uSize);
                            hEnhMetaFile = ::SetWinMetaFileBits(
                                uSize,
                                lpMfBits,
                                NULL,
                                lpMetaFilePict);
                            free(lpMfBits);
                        } catch (std::bad_alloc&) {
                            hr = E_OUTOFMEMORY;
                        }
                    }
                    ::GlobalUnlock(pmedium->hMetaFilePict);
                }
            } else {
                hEnhMetaFile = pmedium->hEnhMetaFile;
            }

            if (NULL == hEnhMetaFile) {
                hr = E_INVALIDARG;
            } else {
                try {
                    paletteDataLocal = AwtDataTransferer::GetPaletteBytes(
                        hEnhMetaFile,
                        OBJ_ENHMETAFILE,
                        FALSE);
                    //paletteDataLocal can be NULL here - it is not a error!

                    UINT uEmfSize = ::GetEnhMetaFileBits(hEnhMetaFile, 0, NULL);
                    DASSERT(uEmfSize != 0);

                    LPBYTE lpEmfBits = (LPBYTE)safe_Malloc(uEmfSize);
                    //no chance to throw exception before catch => no more try-blocks
                    //and no leaks on lpEmfBits

                    VERIFY(::GetEnhMetaFileBits(
                        hEnhMetaFile,
                        uEmfSize,
                        lpEmfBits) == uEmfSize);

                    jbyteArray bytes = env->NewByteArray(uEmfSize);
                    if (NULL == bytes) {
                        hr = E_OUTOFMEMORY;
                    } else {
                        env->SetByteArrayRegion(bytes, 0, uEmfSize, (jbyte*)lpEmfBits);
                        ret = bytes;
                        //bytes is not null here => no CheckRetValue call
                    }
                    free(lpEmfBits);
                } catch (std::bad_alloc&) {
                    hr = E_OUTOFMEMORY;
                }
                if (pmedium->tymed == TYMED_MFPICT) {
                    //because we create it manually
                    ::DeleteEnhMetaFile(hEnhMetaFile);
                }
            }
            break;
        }
        case TYMED_ISTORAGE:
        default:
            hr = E_NOTIMPL;
            break;
    }

    if (FAILED(hr)) {
        //clear exception garbage for hr = E_UNEXPECTED
        ret  = NULL;
    } else {
        switch (fmt) {
        case CF_METAFILEPICT:
        case CF_ENHMETAFILE:
            // If we failed to retrieve palette entries from metafile,
            // fall through and try CF_PALETTE format.
        case CF_DIB: {
            if (JNU_IsNull(env, paletteDataLocal)) {
                jobject paletteData = GetData(CF_PALETTE);

                if (JNU_IsNull(env, paletteData)) {
                    paletteDataLocal =
                        AwtDataTransferer::GetPaletteBytes(NULL, 0, TRUE);
                } else {
                    // GetData() returns a global ref.
                    // We want to deal with local ref.
                    paletteDataLocal = (jbyteArray)env->NewLocalRef(paletteData);
                    env->DeleteGlobalRef(paletteData);
                }
            }
            DASSERT(!JNU_IsNull(env, paletteDataLocal) &&
                    !JNU_IsNull(env, ret));

            jobject concat = AwtDataTransferer::ConcatData(env, paletteDataLocal, ret);
            env->DeleteLocalRef(ret);
            ret = concat;
            hr = CheckRetValue(env, ret);
            break;
        }
        }
    }

    if (!JNU_IsNull(env, paletteDataLocal) ) {
        env->DeleteLocalRef(paletteDataLocal);
    }
    jobject global = NULL;
    if (SUCCEEDED(hr)) {
        global = env->NewGlobalRef(ret);
        env->DeleteLocalRef(ret);
    } else if (E_UNEXPECTED == hr) {
        //internal Java non-GPF exception
        env->ExceptionDescribe();
        env->ExceptionClear();
    } else if (E_OUTOFMEMORY == hr) {
        throw std::bad_alloc();
    } //NULL returns for all other cases
    return global;
}

HRESULT AwtDropTarget::SaveIndexToFile(LPCTSTR pFileName, UINT lIndex)
{
    OLE_TRY
    STGMEDIUM stgmedium;
    OLE_HRT( ExtractNativeData(CF_FILECONTENTS, lIndex, &stgmedium) );
    OLE_NEXT_TRY
        IStreamPtr spSrc;
        if (TYMED_HGLOBAL == stgmedium.tymed) {
            OLE_HRT( CreateStreamOnHGlobal(
                stgmedium.hGlobal,
                FALSE,
                &spSrc
            ));
        } else if(TYMED_ISTREAM == stgmedium.tymed) {
            spSrc = stgmedium.pstm;
        }
        if (NULL == spSrc) {
            OLE_HRT(E_INVALIDARG);
        }
        IStreamPtr spDst;
        OLE_HRT(SHCreateStreamOnFile(
            pFileName,
            STGM_WRITE | STGM_CREATE,
            &spDst
        ));
        STATSTG si = {0};
        OLE_HRT( spSrc->Stat(&si, STATFLAG_NONAME ) );
        OLE_HRT( spSrc->CopyTo(spDst, si.cbSize, NULL, NULL) );
    OLE_CATCH
    ::ReleaseStgMedium(&stgmedium);
    OLE_CATCH
    OLE_RETURN_HR;
}


HRESULT GetTempPathWithSlash(JNIEnv *env, _bstr_t &bsTempPath) /*throws _com_error*/
{
    static _bstr_t _bsPath;

    OLE_TRY
    if (0 == _bsPath.length()) {
        BOOL bSafeEmergency = TRUE;
        TCHAR szPath[MAX_PATH*2];
        JLClass systemCls(env, env->FindClass("java/lang/System"));
        if (systemCls) {
            jmethodID idGetProperty = env->GetStaticMethodID(
                    systemCls,
                    "getProperty",
                    "(Ljava/lang/String;)Ljava/lang/String;");
            if (0 != idGetProperty) {
                static TCHAR param[] = _T("java.io.tmpdir");
                JLString tempdir(env, JNU_NewStringPlatform(env, param));
                if (tempdir) {
                    JLString jsTempPath(env, (jstring)env->CallStaticObjectMethod(
                        systemCls,
                        idGetProperty,
                        (jstring)tempdir
                    ));
                    if (jsTempPath) {
                        _bsPath = (LPCWSTR)JavaStringBuffer(env, jsTempPath);
                        OLE_HRT(SHGetFolderPath(
                            NULL,
                            CSIDL_WINDOWS,
                            NULL,
                            0,
                            szPath));
                        _tcscat(szPath, _T("\\"));
                        //Dead environment block leads to fact that windows folder becomes temporary path.
                        //For example while jtreg execution %TEMP%, %TMP% and etc. aren't defined.
                        bSafeEmergency = ( 0 == _tcsicmp(_bsPath, szPath) );
                    }
                }
            }
        }
        if (bSafeEmergency) {
            OLE_HRT(SHGetFolderPath(
                NULL,
                CSIDL_INTERNET_CACHE|CSIDL_FLAG_CREATE,
                NULL,
                0,
                szPath));
            _tcscat(szPath, _T("\\"));
            _bsPath = szPath;
        }
    }
    OLE_CATCH
    bsTempPath = _bsPath;
    OLE_RETURN_HR
}

jobject AwtDropTarget::ConvertMemoryMappedData(JNIEnv* env, jlong fmt, STGMEDIUM *pmedium) /*throw std::bad_alloc */
{
    jobject retObj = NULL;
    OLE_TRY
    if (TYMED_HGLOBAL != pmedium->tymed) {
        OLE_HRT(E_INVALIDARG);
    }
    FILEGROUPDESCRIPTORA *pfgdHead = (FILEGROUPDESCRIPTORA *)::GlobalLock(pmedium->hGlobal);
    if (NULL == pfgdHead) {
        OLE_HRT(E_INVALIDARG);
    }
    OLE_NEXT_TRY
        if (0 == pfgdHead->cItems) {
            OLE_HRT(E_INVALIDARG);
        }
        IStreamPtr spFileNames;
        OLE_HRT( CreateStreamOnHGlobal(
            NULL,
            TRUE,
            &spFileNames
        ));

        _bstr_t sbTempDir;
        OLE_HRT( GetTempPathWithSlash(env, sbTempDir) );
        FILEDESCRIPTORA *pfgdA = pfgdHead->fgd;
        FILEDESCRIPTORW *pfgdW = (FILEDESCRIPTORW *)pfgdA;
        for (UINT i = 0; i < pfgdHead->cItems; ++i) {
            _bstr_t stFullName(sbTempDir);
            if(CF_FILEGROUPDESCRIPTORA == fmt) {
                stFullName += pfgdA->cFileName; //as CHAR
                ++pfgdA;
            } else {
                stFullName += pfgdW->cFileName; //as WCHAR
                ++pfgdW;
            }
            OLE_HRT(SaveIndexToFile(
                stFullName,
                i));
            //write to stream with zero terminator
            OLE_HRT( spFileNames->Write((LPCTSTR)stFullName, (stFullName.length() + 1)*sizeof(TCHAR), NULL) );
        }
        OLE_HRT( spFileNames->Write(_T(""), sizeof(TCHAR), NULL) );
        STATSTG st;
        OLE_HRT( spFileNames->Stat(&st, STATFLAG_NONAME) );

        //empty lists was forbidden: pfgdHead->cItems > 0
        jbyteArray bytes = env->NewByteArray(st.cbSize.LowPart);
        if (NULL == bytes) {
            OLE_HRT(E_OUTOFMEMORY);
        } else {
            HGLOBAL glob;
            OLE_HRT(GetHGlobalFromStream(spFileNames, &glob));
            jbyte *pFileListWithDoubleZeroTerminator = (jbyte *)::GlobalLock(glob);
            env->SetByteArrayRegion(bytes, 0, st.cbSize.LowPart, pFileListWithDoubleZeroTerminator);
            ::GlobalUnlock(pFileListWithDoubleZeroTerminator);
            retObj = bytes;
        }
        //std::bad_alloc could happen in JStringBuffer
        //no leaks due to wrapper
    OLE_CATCH_BAD_ALLOC
    ::GlobalUnlock(pmedium->hGlobal);
    OLE_CATCH
    jobject global = NULL;
    if (SUCCEEDED(OLE_HR)) {
        global = env->NewGlobalRef(retObj);
        env->DeleteLocalRef(retObj);
    } else if (E_OUTOFMEMORY == OLE_HR) {
        throw std::bad_alloc();
    }
    return global;
}

jobject AwtDropTarget::GetData(jlong fmt)
{
    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    if (env->EnsureLocalCapacity(1) < 0) {
        return (jobject)NULL;
    }
    jobject ret = NULL;
    OLE_TRY
    STGMEDIUM stgmedium;
    OLE_HRT( ExtractNativeData(fmt, -1, &stgmedium) );
    OLE_NEXT_TRY
        if (CF_FILEGROUPDESCRIPTORA == fmt ||
            CF_FILEGROUPDESCRIPTORW == fmt)
        {
            ret = ConvertMemoryMappedData(env, fmt, &stgmedium);
        } else {
            ret = ConvertNativeData(env, fmt, &stgmedium);
        }
    OLE_CATCH_BAD_ALLOC
    ::ReleaseStgMedium(&stgmedium);
    OLE_CATCH
    if (E_OUTOFMEMORY == OLE_HR) {
        throw std::bad_alloc();
    }
    return ret;
}

/**
 *
 */

int __cdecl AwtDropTarget::_compar(const void* first, const void* second) {
    FORMATETC *fp = (FORMATETC *)first;
    FORMATETC *sp = (FORMATETC *)second;

    if (fp->cfFormat == sp->cfFormat) {
        return fp->tymed - sp->tymed;
    }

    return fp->cfFormat - sp->cfFormat;
}

const unsigned int AwtDropTarget::CACHE_INCR = 16;

void AwtDropTarget::LoadCache(IDataObject* pDataObj) {
    JNIEnv*      env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    unsigned int cnt = 0;
    HRESULT      res;
    IEnumFORMATETC* pEnumFormatEtc = NULL;

    if (m_dataObject != (IDataObject*)NULL) UnloadCache();

    if (!IsLocalDnD()) {
        SetCurrentDnDDataObject(pDataObj);
    }

    (m_dataObject = pDataObj)->AddRef();

    res = m_dataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormatEtc);

    if (res == S_OK) {
    for (;;) {

        FORMATETC tmp;
        ULONG     actual = 1;

            res = pEnumFormatEtc->Next((ULONG)1, &tmp, &actual);
            if (res == S_FALSE)
                break;

        if (!(tmp.cfFormat  >= 1                &&
              tmp.ptd       == NULL             &&
                (tmp.lindex == -1 || CF_FILECONTENTS==tmp.cfFormat) &&
              tmp.dwAspect  == DVASPECT_CONTENT &&
                ( tmp.tymed == TYMED_HGLOBAL ||
               tmp.tymed    == TYMED_FILE       ||
               tmp.tymed    == TYMED_ISTREAM    ||
               tmp.tymed    == TYMED_GDI        ||
               tmp.tymed    == TYMED_MFPICT     ||
               tmp.tymed    == TYMED_ENHMF
              ) // but not ISTORAGE
             )
            )
                continue;

        if (m_dataObject->QueryGetData(&tmp) != S_OK) continue;

        if (m_nformats % CACHE_INCR == 0) {
            m_formats = (FORMATETC *)SAFE_SIZE_ARRAY_REALLOC(safe_Realloc, m_formats,
                                                  CACHE_INCR + m_nformats,
                                                  sizeof(FORMATETC));
        }

        memcpy(m_formats + m_nformats, &tmp, sizeof(FORMATETC));

        m_nformats++;
    }

        // We are responsible for releasing the enumerator.
        pEnumFormatEtc->Release();
    }

    if (m_nformats > 0) {
        qsort((void*)m_formats, m_nformats, sizeof(FORMATETC),
              AwtDropTarget::_compar);
    }

    if (m_cfFormats != NULL) {
        env->DeleteGlobalRef(m_cfFormats);
    }
    jlongArray l_cfFormats = env->NewLongArray(m_nformats);
    if (l_cfFormats == NULL) {
        throw std::bad_alloc();
    }
    m_cfFormats = (jlongArray)env->NewGlobalRef(l_cfFormats);
    env->DeleteLocalRef(l_cfFormats);

    jboolean isCopy;
    jlong *lcfFormats = env->GetLongArrayElements(m_cfFormats, &isCopy),
        *saveFormats = lcfFormats;

    for (unsigned int i = 0; i < m_nformats; i++, lcfFormats++) {
        *lcfFormats = m_formats[i].cfFormat;
    }

    env->ReleaseLongArrayElements(m_cfFormats, saveFormats, 0);
}

/**
 * UnloadCache
 */

void AwtDropTarget::UnloadCache() {
    if (m_dataObject == (IDataObject*)NULL) return;

    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    free((void*)m_formats);
    m_formats  = (FORMATETC *)NULL;
    m_nformats = 0;

    // fix for 6212440: on application shutdown, this object's
    // destruction might be suppressed due to dangling COM references.
    // This method is called from the destructor.
    // On destruction, VM might be shut down already, so we should make
    // a null check on env.
    if (env) {
        env->DeleteGlobalRef(m_cfFormats);
    }
    m_cfFormats = NULL;

    if (!IsLocalDnD()) {
        DASSERT(IsCurrentDnDDataObject(m_dataObject));
        SetCurrentDnDDataObject(NULL);
    }

    m_dataObject->Release();
    m_dataObject = (IDataObject*)NULL;
}

/**
 * DragCleanup
 */

void AwtDropTarget::DragCleanup(void) {
    UnloadCache();
}

BOOL AwtDropTarget::IsLocalDataObject(IDataObject __RPC_FAR *pDataObject) {
    BOOL local = FALSE;

    if (pDataObject != NULL) {
        FORMATETC format;
        STGMEDIUM stgmedium;

        format.cfFormat = AwtDragSource::PROCESS_ID_FORMAT;
        format.ptd      = NULL;
        format.dwAspect = DVASPECT_CONTENT;
        format.lindex   = -1;
        format.tymed    = TYMED_HGLOBAL;

        if (pDataObject->GetData(&format, &stgmedium) == S_OK) {
            ::SetLastError(0); // clear error
            // Warning C4244.
            SIZE_T size = ::GlobalSize(stgmedium.hGlobal);
            if (size < sizeof(DWORD) || ::GetLastError() != 0) {
                ::SetLastError(0); // clear error
            } else {

                DWORD id = ::CoGetCurrentProcess();

                LPVOID data = ::GlobalLock(stgmedium.hGlobal);
                if (memcmp(data, &id, sizeof(id)) == 0) {
                    local = TRUE;
                }
                ::GlobalUnlock(stgmedium.hGlobal);
            }
            ::ReleaseStgMedium(&stgmedium);
        }
    }

    return local;
}

DECLARE_JAVA_CLASS(dTCClazz, "sun/awt/windows/WDropTargetContextPeer")

jobject
AwtDropTarget::call_dTCcreate(JNIEnv* env) {
    DECLARE_STATIC_OBJECT_JAVA_METHOD(dTCcreate, dTCClazz,
                                      "getWDropTargetContextPeer",
                                      "()Lsun/awt/windows/WDropTargetContextPeer;");
    return env->CallStaticObjectMethod(clazz, dTCcreate);
}

jint
AwtDropTarget::call_dTCenter(JNIEnv* env, jobject self, jobject component, jint x, jint y,
              jint dropAction, jint actions, jlongArray formats,
              jlong nativeCtxt) {
    DECLARE_JINT_JAVA_METHOD(dTCenter, dTCClazz, "handleEnterMessage",
                            "(Ljava/awt/Component;IIII[JJ)I");
    DASSERT(!JNU_IsNull(env, self));
    return env->CallIntMethod(self, dTCenter, component, x, y, dropAction,
                              actions, formats, nativeCtxt);
}

void
AwtDropTarget::call_dTCexit(JNIEnv* env, jobject self, jobject component, jlong nativeCtxt) {
    DECLARE_VOID_JAVA_METHOD(dTCexit, dTCClazz, "handleExitMessage",
                            "(Ljava/awt/Component;J)V");
    DASSERT(!JNU_IsNull(env, self));
    env->CallVoidMethod(self, dTCexit, component, nativeCtxt);
}

jint
AwtDropTarget::call_dTCmotion(JNIEnv* env, jobject self, jobject component, jint x, jint y,
               jint dropAction, jint actions, jlongArray formats,
               jlong nativeCtxt) {
    DECLARE_JINT_JAVA_METHOD(dTCmotion, dTCClazz, "handleMotionMessage",
                            "(Ljava/awt/Component;IIII[JJ)I");
    DASSERT(!JNU_IsNull(env, self));
    return env->CallIntMethod(self, dTCmotion, component, x, y,
                                 dropAction, actions, formats, nativeCtxt);
}

void
AwtDropTarget::call_dTCdrop(JNIEnv* env, jobject self, jobject component, jint x, jint y,
             jint dropAction, jint actions, jlongArray formats,
             jlong nativeCtxt) {
    DECLARE_VOID_JAVA_METHOD(dTCdrop, dTCClazz, "handleDropMessage",
                            "(Ljava/awt/Component;IIII[JJ)V");
    DASSERT(!JNU_IsNull(env, self));
    env->CallVoidMethod(self, dTCdrop, component, x, y,
                           dropAction, actions, formats, nativeCtxt);
}

jobject
AwtDropTarget::call_dTCgetfs(JNIEnv* env, jstring fileName, jlong stgmedium) {
    DECLARE_STATIC_OBJECT_JAVA_METHOD(dTCgetfs, dTCClazz, "getFileStream",
                                      "(Ljava/lang/String;J)Ljava/io/FileInputStream;");
    return env->CallStaticObjectMethod(clazz, dTCgetfs, fileName, stgmedium);
}

jobject
AwtDropTarget::call_dTCgetis(JNIEnv* env, jlong istream) {
    DECLARE_STATIC_OBJECT_JAVA_METHOD(dTCgetis, dTCClazz, "getIStream",
                                      "(J)Ljava/lang/Object;");
    return env->CallStaticObjectMethod(clazz, dTCgetis, istream);
}

/*****************************************************************************/

jclass WDTCPIStreamWrapper::javaIOExceptionClazz = (jclass)NULL;

/**
 * construct a wrapper
 */

WDTCPIStreamWrapper::WDTCPIStreamWrapper(STGMEDIUM* stgmedium) {
    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    m_stgmedium = *stgmedium;
    m_istream   = stgmedium->pstm;
    m_istream->AddRef();
    m_mutex     = ::CreateMutex(NULL, FALSE, NULL);

    if (javaIOExceptionClazz == (jclass)NULL) {
        javaIOExceptionClazz = env->FindClass("java/io/IOException");

        if (JNU_IsNull(env, javaIOExceptionClazz)) {
            env->ThrowNew(env->FindClass("java/lang/ClassNotFoundException"),
                          "Cant find java/io/IOException"
            );
        }
    }
}

/**
 * destroy a wrapper
 */

WDTCPIStreamWrapper::~WDTCPIStreamWrapper() {
    ::CloseHandle(m_mutex);
    m_istream->Release();
    ::ReleaseStgMedium(&m_stgmedium);
}

/**
 * return available data
 */

jint WDTCPIStreamWrapper::DoAvailable(WDTCPIStreamWrapper* istream) {
    WDTCPIStreamWrapperRec iswr = { istream, 0 };

    AwtToolkit::GetInstance().WaitForSingleObject(istream->m_mutex);

    AwtToolkit::GetInstance().InvokeFunctionLater( _Available, &iswr);

    istream->WaitUntilSignalled(FALSE);

    return iswr.ret;
}

/**
 * return available data
 */

void WDTCPIStreamWrapper::_Available(void *param) {
    WDTCPIStreamWrapperPtr iswrp = (WDTCPIStreamWrapperPtr)param;

    iswrp->ret = (iswrp->istream)->Available();

    iswrp->istream->Signal();
}

/**
 * return available data
 */

jint WDTCPIStreamWrapper::Available() {
    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    if (m_istream->Stat(&m_statstg, STATFLAG_NONAME) != S_OK) {
        env->ThrowNew(javaIOExceptionClazz, "IStream::Stat() failed");
        return 0;
    }

    if (m_statstg.cbSize.QuadPart > 0x7ffffffL) {
        env->ThrowNew(javaIOExceptionClazz, "IStream::Stat() cbSize > 0x7ffffff");
        return 0;
    }

    return (jint)m_statstg.cbSize.LowPart;
}

/**
 * read 1 byte
 */

jint WDTCPIStreamWrapper::DoRead(WDTCPIStreamWrapper* istream) {
    WDTCPIStreamWrapperRec iswr = { istream, 0 };

    AwtToolkit::GetInstance().WaitForSingleObject(istream->m_mutex);

    AwtToolkit::GetInstance().InvokeFunctionLater(_Read, &iswr);

    istream->WaitUntilSignalled(FALSE);

    return iswr.ret;
}

/**
 * read 1 byte
 */

void WDTCPIStreamWrapper::_Read(void* param) {
    WDTCPIStreamWrapperPtr iswrp = (WDTCPIStreamWrapperPtr)param;

    iswrp->ret = (iswrp->istream)->Read();

    iswrp->istream->Signal();
}

/**
 * read 1 byte
 */

jint WDTCPIStreamWrapper::Read() {
    JNIEnv* env    = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    jint    b      = 0;
    ULONG   actual = 0;
    HRESULT res;

    switch (res = m_istream->Read((void *)&b, (ULONG)1, &actual)) {
        case S_FALSE:
            return (jint)-1;

        case S_OK:
            return (jint)(actual == 0 ? -1 : b);

        default:
            env->ThrowNew(javaIOExceptionClazz, "IStream::Read failed");
    }
    return (jint)-1;
}

/**
 * read Buffer
 */

jint WDTCPIStreamWrapper::DoReadBytes(WDTCPIStreamWrapper* istream, jbyteArray array, jint off, jint len) {
    WDTCPIStreamWrapperReadBytesRec iswrbr = { istream, 0, array, off, len };

    AwtToolkit::GetInstance().WaitForSingleObject(istream->m_mutex);

    AwtToolkit::GetInstance().InvokeFunctionLater(_ReadBytes, &iswrbr);

    istream->WaitUntilSignalled(FALSE);

    return iswrbr.ret;
}

/**
 * read buffer
 */

void WDTCPIStreamWrapper::_ReadBytes(void*  param) {
    WDTCPIStreamWrapperReadBytesPtr iswrbrp =
        (WDTCPIStreamWrapperReadBytesPtr)param;

    iswrbrp->ret = (iswrbrp->istream)->ReadBytes(iswrbrp->array,
                                                 iswrbrp->off,
                                                 iswrbrp->len);
    iswrbrp->istream->Signal();
}

/**
 * read buffer
 */

jint WDTCPIStreamWrapper::ReadBytes(jbyteArray buf, jint off, jint len) {
    JNIEnv*  env     = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    jboolean isCopy  = JNI_FALSE;
    ULONG    actual  = 0;
    jbyte*   local   = env->GetByteArrayElements(buf, &isCopy);
    HRESULT  res;

    switch (res = m_istream->Read((void *)(local + off), (ULONG)len, &actual)) {
        case S_FALSE:
        case S_OK: {
            int eof = (actual == 0);

            env->ReleaseByteArrayElements(buf, local, !eof ? 0 : JNI_ABORT);
            return (jint)(!eof ? actual : -1);
        }

        default:
            env->ReleaseByteArrayElements(buf, local, JNI_ABORT);
            env->ThrowNew(javaIOExceptionClazz, "IStream::Read failed");
    }

    return (jint)-1;
}

/**
 * close
 */

void WDTCPIStreamWrapper::DoClose(WDTCPIStreamWrapper* istream) {
    AwtToolkit::GetInstance().InvokeFunctionLater(_Close, istream);
}

/**
 * close
 */

void WDTCPIStreamWrapper::_Close(void* param) {
    ((WDTCPIStreamWrapper*)param)->Close();
}

/**
 * close
 */

void WDTCPIStreamWrapper::Close() {
    delete this;
}

/*****************************************************************************/

extern "C" {

/**
 * awt_dnd_initialize: initial DnD system
 */

void awt_dnd_initialize() {
    ::OleInitialize((LPVOID)NULL);
}

/**
 * awt_dnd_uninitialize: deactivate DnD system
 */

void awt_dnd_uninitialize() {
    ::OleUninitialize();
}

/**
 * convertActionsToDROPEFFECT
 */

DWORD convertActionsToDROPEFFECT(jint actions) {
    DWORD effects = DROPEFFECT_NONE;

    if (actions & java_awt_dnd_DnDConstants_ACTION_LINK) effects |= DROPEFFECT_LINK;
    if (actions & java_awt_dnd_DnDConstants_ACTION_MOVE) effects |= DROPEFFECT_MOVE;
    if (actions & java_awt_dnd_DnDConstants_ACTION_COPY) effects |= DROPEFFECT_COPY;
    return effects;
}

/**
 * convertDROPEFFECTToAction
 */

jint convertDROPEFFECTToActions(DWORD effects) {
    jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;

    if (effects & DROPEFFECT_LINK) actions |= java_awt_dnd_DnDConstants_ACTION_LINK;
    if (effects & DROPEFFECT_MOVE) actions |= java_awt_dnd_DnDConstants_ACTION_MOVE;
    if (effects & DROPEFFECT_COPY) actions |= java_awt_dnd_DnDConstants_ACTION_COPY;

    return actions;
}

/**
 * map keyboard modifiers to a DROPEFFECT
 */

DWORD mapModsToDROPEFFECT(DWORD effects, DWORD mods) {
    DWORD ret = DROPEFFECT_NONE;

    /*
     * Fix for 4285634.
     * Calculate the drop action to match Motif DnD behavior.
     * If the user selects an operation (by pressing a modifier key),
     * return the selected operation or DROPEFFECT_NONE if the selected
     * operation is not supported by the drag source.
     * If the user doesn't select an operation search the set of operations
     * supported by the drag source for DROPEFFECT_MOVE, then for
     * DROPEFFECT_COPY, then for DROPEFFECT_LINK and return the first operation
     * found.
     */
    switch (mods & (MK_CONTROL | MK_SHIFT)) {
        case MK_CONTROL:
            ret = DROPEFFECT_COPY;
        break;

        case MK_CONTROL | MK_SHIFT:
            ret = DROPEFFECT_LINK;
        break;

        case MK_SHIFT:
            ret = DROPEFFECT_MOVE;
        break;

        default:
            if (effects & DROPEFFECT_MOVE) {
                ret = DROPEFFECT_MOVE;
            } else if (effects & DROPEFFECT_COPY) {
                ret = DROPEFFECT_COPY;
            } else if (effects & DROPEFFECT_LINK) {
                ret = DROPEFFECT_LINK;
            }
            break;
    }

    return ret & effects;
}

/**
 * downcall to fetch data ... gets scheduled on message thread
 */

JNIEXPORT jobject JNICALL Java_sun_awt_windows_WDropTargetContextPeer_getData(JNIEnv* env, jobject self, jlong dropTarget, jlong format) {
    TRY;

    AwtDropTarget* pDropTarget = (AwtDropTarget*)dropTarget;

    DASSERT(!::IsBadReadPtr(pDropTarget, sizeof(AwtDropTarget)));
    return pDropTarget->DoGetData(format);

    CATCH_BAD_ALLOC_RET(NULL);
}

/**
 * downcall to signal drop done ... gets scheduled on message thread
 */

JNIEXPORT void JNICALL
Java_sun_awt_windows_WDropTargetContextPeer_dropDone(JNIEnv* env, jobject self,
                             jlong dropTarget, jboolean success, jint actions) {
    TRY_NO_HANG;

    AwtDropTarget* pDropTarget = (AwtDropTarget*)dropTarget;

    DASSERT(!::IsBadReadPtr(pDropTarget, sizeof(AwtDropTarget)));
    pDropTarget->DoDropDone(success, actions);

    CATCH_BAD_ALLOC;
}

/**
 * downcall to free up storage medium for FileStream
 */

JNIEXPORT void JNICALL Java_sun_awt_windows_WDropTargetContextPeerFileStream_freeStgMedium(JNIEnv* env, jobject self, jlong stgmedium) {
    TRY;

    ::ReleaseStgMedium((STGMEDIUM*)stgmedium);

    free((void*)stgmedium);

    CATCH_BAD_ALLOC;
}

/**
 *
 */

JNIEXPORT jint JNICALL Java_sun_awt_windows_WDropTargetContextPeerIStream_Available(JNIEnv* env, jobject self, jlong istream) {
    TRY;

    return WDTCPIStreamWrapper::DoAvailable((WDTCPIStreamWrapper*)istream);

    CATCH_BAD_ALLOC_RET(0);
}

/**
 *
 */

JNIEXPORT jint JNICALL Java_sun_awt_windows_WDropTargetContextPeerIStream_Read(JNIEnv* env, jobject self, jlong istream) {
    TRY;

    return WDTCPIStreamWrapper::DoRead((WDTCPIStreamWrapper*)istream);

    CATCH_BAD_ALLOC_RET(0);
}

/**
 *
 */

JNIEXPORT jint JNICALL Java_sun_awt_windows_WDropTargetContextPeerIStream_ReadBytes(JNIEnv* env, jobject self, jlong istream, jbyteArray buf, jint off, jint len) {
    TRY;

    return WDTCPIStreamWrapper::DoReadBytes((WDTCPIStreamWrapper*)istream, buf, off, len);

    CATCH_BAD_ALLOC_RET(0);
}

/**
 *
 */

JNIEXPORT void JNICALL Java_sun_awt_windows_WDropTargetContextPeerIStream_Close(JNIEnv* env, jobject self, jlong istream) {
    TRY_NO_VERIFY;

    WDTCPIStreamWrapper::DoClose((WDTCPIStreamWrapper*)istream);

    CATCH_BAD_ALLOC;
}

} /* extern "C" */

Other Java examples (source code examples)

Here is a short list of links related to this Java awt_DnDDT.cpp source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.