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

Java example source code file (awt_DataTransferer.cpp)

This example Java source code file (awt_DataTransferer.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

bits_per_pixel, catch_bad_alloc_ret, dassert, e_outofmemory, hresult_from_win32, jnicall, jniexport, jnu_isnull, lpbyte, mm_himetric, null, try, uint, verify

The awt_DataTransferer.cpp Java example source code

/*
 * Copyright (c) 2000, 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 "awt_DataTransferer.h"
#include "awt_DnDDT.h"
#include "awt_TextComponent.h"
#include <shlobj.h>
#include <shellapi.h>
#include <sun_awt_windows_WDataTransferer.h>

#include "locale_str.h"

#define GALLOCFLG (GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT)
#define WIN_TO_JAVA_PIXEL(r, g, b) (0xFF000000 | (r) << 16 | (g) << 8  | (b) << 0)

DECLARE_JAVA_CLASS(dataTransfererClazz, "sun/awt/datatransfer/DataTransferer");

jobject
AwtDataTransferer::GetDataTransferer(JNIEnv* env) {
    DECLARE_STATIC_OBJECT_JAVA_METHOD(getInstanceMethodID, dataTransfererClazz,
                                      "getInstance",
                                      "()Lsun/awt/datatransfer/DataTransferer;");
    return env->CallStaticObjectMethod(clazz, getInstanceMethodID);
}

jbyteArray
AwtDataTransferer::ConvertData(JNIEnv* env, jobject source, jobject contents,
                               jlong format, jobject formatMap) {
    jobject transferer = GetDataTransferer(env);

    if (!JNU_IsNull(env, transferer)) {
        jbyteArray ret = NULL;
        DECLARE_OBJECT_JAVA_METHOD(convertDataMethodID, dataTransfererClazz,
                                   "convertData",
                                   "(Ljava/lang/Object;Ljava/awt/datatransfer/Transferable;JLjava/util/Map;Z)[B");

        ret = (jbyteArray)env->CallObjectMethod(transferer, convertDataMethodID,
                                                source, contents, format,
                                                formatMap, AwtToolkit::IsMainThread());

        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
            env->ExceptionDescribe();
            env->ExceptionClear();
        }

        env->DeleteLocalRef(transferer);

        return ret;
    } else {
        return NULL;
    }
}

jobject
AwtDataTransferer::ConcatData(JNIEnv* env, jobject obj1, jobject obj2) {
    jobject transferer = GetDataTransferer(env);

    if (!JNU_IsNull(env, transferer)) {
        jobject ret = NULL;
        DECLARE_OBJECT_JAVA_METHOD(concatDataMethodID, dataTransfererClazz,
                                   "concatData",
                                   "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

        ret = env->CallObjectMethod(transferer, concatDataMethodID, obj1, obj2);

        if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) {
            env->ExceptionDescribe();
            env->ExceptionClear();
        }

        env->DeleteLocalRef(transferer);

        return ret;
    } else {
        return NULL;
    }
}

/**
 * This routine retrieves palette entries from enhanced metafile or
 * a logical color palette, builds appropriate LOGPALETTE structure,
 * writes it into a created Java byte array and returns a local
 * reference to the array.
 * This routine is used for image data transfer.
 *
 * @param hGdiObj - a handle to the GDI object to retrieve palette entries from,
 *        it can be a handle to either a logical color palette (OBJ_PAL type)
 *        or an enhanced metafile (OBJ_ENHMETAFILE). If it is neither of these
 *        types the routine fails(see bFailSafe).
 * @param dwGdiObjType - a type of the passed GDI object. It should be specified
 *        if the type of the passed GDI object is known to the caller. Otherwise
 *        pass 0.
 * @param bFailSafe - if FALSE, the routine will return NULL in case of failure,
 *        otherwise it will return an array with empty LOGPALETTE structure
 *        in case of failure.
 * @return a local reference to Java byte array which contains LOGPALETTE
 *        structure which defines a logical color palette or a palette of
 *        an enhanced metafile.
 */
jbyteArray
AwtDataTransferer::GetPaletteBytes(HGDIOBJ hGdiObj, DWORD dwGdiObjType,
                                   BOOL bFailSafe) {

    if (hGdiObj == NULL) {
        dwGdiObjType = 0;
    } else if (dwGdiObjType == 0) {
        dwGdiObjType = ::GetObjectType(hGdiObj);
    } else {
        DASSERT(::GetObjectType(hGdiObj) == dwGdiObjType);
    }

    if (!bFailSafe && dwGdiObjType == 0) {
        return NULL;
    }

    UINT nEntries = 0;

    switch (dwGdiObjType) {
    case OBJ_PAL:
        nEntries =
            ::GetPaletteEntries((HPALETTE)hGdiObj, 0, 0, NULL);
        break;
    case OBJ_ENHMETAFILE:
        nEntries =
            ::GetEnhMetaFilePaletteEntries((HENHMETAFILE)hGdiObj, 0, NULL);
        break;
    }

    if (!bFailSafe && (nEntries == 0 || nEntries == GDI_ERROR)) {
        return NULL;
    }

    JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    jsize size = sizeof(LOGPALETTE) + nEntries * sizeof(PALETTEENTRY);

    jbyteArray paletteBytes = env->NewByteArray(size);
    if (JNU_IsNull(env, paletteBytes)) {
        throw std::bad_alloc();
    }

    LOGPALETTE* pLogPalette =
        (LOGPALETTE*)env->GetPrimitiveArrayCritical(paletteBytes, NULL);
    PALETTEENTRY* pPalEntries = (PALETTEENTRY*)pLogPalette->palPalEntry;

    pLogPalette->palVersion = 0x300;
    pLogPalette->palNumEntries = nEntries;

    switch (dwGdiObjType) {
    case OBJ_PAL:
        VERIFY(::GetPaletteEntries((HPALETTE)hGdiObj, 0, nEntries,
                                   pPalEntries) == nEntries);
        break;
    case OBJ_ENHMETAFILE:
        VERIFY(::GetEnhMetaFilePaletteEntries((HENHMETAFILE)hGdiObj, nEntries,
                                              pPalEntries) == nEntries);
        break;
    }

    env->ReleasePrimitiveArrayCritical(paletteBytes, pLogPalette, 0);

    return paletteBytes;
}

jbyteArray
AwtDataTransferer::LCIDToTextEncoding(JNIEnv *env, LCID lcid) {
    LANGID langID = LANGIDFROMLCID(lcid);
    const char *encoding = getEncodingFromLangID(langID);

    // Warning C4244.
    // Cast SIZE_T (__int64 on 64-bit/unsigned int on 32-bit)
    // to jsize (long).
    // We assume that the encoding name length cannot exceed INT_MAX.
    jsize length = (jsize)strlen(encoding);

    jbyteArray retval = env->NewByteArray(length);
    if (retval == NULL) {
        throw std::bad_alloc();
    }
    env->SetByteArrayRegion(retval, 0, length, (jbyte *)encoding);
    free((void *)encoding);
    return retval;
}

static VOID CALLBACK
IdleFunc() {
    /*
     * Fix for 4485987 and 4669873.
     * If IdleFunc is a noop, the secondary message pump occasionally occupies
     * all processor time and causes drag freezes. GetQueueStatus is needed to
     * mark all messages that are currently in the queue as old, otherwise
     * WaitMessage will return immediatelly as we selectively get messages from
     * the queue.
     */
    ::WaitMessage();
    ::GetQueueStatus(QS_ALLINPUT);
}

static BOOL CALLBACK
PeekMessageFunc(MSG& msg) {
    return ::PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE) ||
           ::PeekMessage(&msg, NULL, WM_AWT_INVOKE_METHOD, WM_AWT_INVOKE_METHOD, PM_REMOVE) ||
           ::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE);
}

void
AwtDataTransferer::SecondaryMessageLoop() {
    DASSERT(AwtToolkit::MainThread() == ::GetCurrentThreadId());

    AwtToolkit::GetInstance().MessageLoop(IdleFunc,
                                          PeekMessageFunc);
}

extern "C" {

/*
 * Class:     sun_awt_datatransfer_DataTransferer
 * Method:    draqQueryFile
 * Signature: ([B)[Ljava/lang/String;
 */
JNIEXPORT jobjectArray JNICALL
Java_sun_awt_windows_WDataTransferer_dragQueryFile
    (JNIEnv *env, jobject obj, jbyteArray bytes)
{
    TRY;

    /*
     * Fix for the BugTraq ID 4327064 - inter-jvm DnD crashes the droping jvm.
     * On Win9X DragQueryFile() doesn't accept a pointer to the local help as the first
     * argument, so we should dump the bits into global memory.
     */
    UINT size = env->GetArrayLength(bytes);
    HGLOBAL hglobal = NULL;
    jbyte *bBytes = NULL;
    HDROP hdrop = NULL;
    LPTSTR buffer = NULL;

    hglobal = ::GlobalAlloc(GALLOCFLG, size);

    if (hglobal == NULL) {
        throw std::bad_alloc();
    }

    try {

        bBytes = (jbyte*)::GlobalLock(hglobal);
        env->GetByteArrayRegion(bytes, 0, size, bBytes);

        hdrop = (HDROP)bBytes;

        UINT nFilenames = ::DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0);

        jclass str_clazz = env->FindClass("java/lang/String");
        DASSERT(str_clazz != NULL);
        jobjectArray filenames = env->NewObjectArray(nFilenames, str_clazz,
                                                     NULL);
        if (filenames == NULL) {
            throw std::bad_alloc();
        }

        UINT bufsize = 512; // in characters, not in bytes
        buffer = (LPTSTR)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, bufsize, sizeof(TCHAR));

        for (UINT i = 0; i < nFilenames; i++) {
            UINT size = ::DragQueryFile(hdrop, i, NULL, 0);
            if (size > bufsize) {
                bufsize = size;
                buffer = (LPTSTR)SAFE_SIZE_ARRAY_REALLOC(safe_Realloc, buffer, bufsize, sizeof(TCHAR));
            }
            ::DragQueryFile(hdrop, i, buffer, bufsize);

            jstring name = JNU_NewStringPlatform(env, buffer);
            if (name == NULL) {
                throw std::bad_alloc();
            }

            env->SetObjectArrayElement(filenames, i, name);
        }

        free(buffer);
        ::GlobalUnlock(hglobal);
        ::GlobalFree(hglobal);
        return filenames;

    } catch (std::bad_alloc&) {
        free(buffer);
        ::GlobalUnlock(hglobal);
        ::GlobalFree(hglobal);
        throw;
    }

    CATCH_BAD_ALLOC_RET(NULL);
}

/*
 * Class:     sun_awt_windows_WDataTransferer
 * Method:    platformImageBytesToImageData
 * Signature: ([BI)[I
 */
JNIEXPORT jintArray JNICALL
Java_sun_awt_windows_WDataTransferer_platformImageBytesToImageData(
    JNIEnv *env, jobject self, jbyteArray bytes, jlong format) {

    TRY;

    HDC hdc = NULL;

    LOGPALETTE* pLogPalette = NULL;
    WORD uPaletteEntries = 0;
    SIZE_T uOffset = 0;
    HPALETTE hPalette = NULL;
    HPALETTE hOldPalette = NULL;

    BITMAPINFO* pSrcBmi = NULL;
    BITMAPINFOHEADER* pSrcBmih = NULL;
    LPVOID pSrcBits = NULL;
    BITMAPINFO* pDstBmi = NULL;
    BITMAPINFOHEADER* pDstBmih = NULL;
    LPVOID pDstBits = NULL;

    LPBYTE lpEnhMetaFileBits = NULL;
    HENHMETAFILE hEnhMetaFile = NULL;

    HBITMAP hDibSection = NULL;
    HBITMAP hOldBitmap = NULL;
    jintArray buffer = NULL;
    LONG width = 0;
    LONG height = 0;
    int numPixels = 0;

    if (JNU_IsNull(env, bytes)) {
        return NULL;
    }

    jsize size = env->GetArrayLength(bytes);
    if (size == 0) {
        return NULL;
    }

    jbyte* bBytes = (jbyte*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, size, sizeof(jbyte));

    try {

        env->GetByteArrayRegion(bytes, 0, size, bBytes);

        pLogPalette = (LOGPALETTE*)bBytes;
        uPaletteEntries = pLogPalette->palNumEntries;
        uOffset = sizeof(LOGPALETTE) + uPaletteEntries * sizeof(PALETTEENTRY);
        DASSERT(uOffset < (SIZE_T)size);

        if (uPaletteEntries == 0) {
            pLogPalette = NULL;
        }

        hdc = ::CreateCompatibleDC(NULL);
        if (hdc == NULL) {
            free(bBytes);
            return NULL;
        }

        switch (format) {
        case CF_DIB:

            pSrcBmi = (BITMAPINFO*)((LPSTR)bBytes + uOffset);
            pSrcBmih = &pSrcBmi->bmiHeader;

            width = pSrcBmih->biWidth;
            height = abs(pSrcBmih->biHeight);

            {
                DWORD nColorEntries = 0;

                switch (pSrcBmih->biBitCount) {
                case  0: nColorEntries = 0; break;
                case  1: nColorEntries = 2; break;
                case  4:
                case  8:
                    nColorEntries = (pSrcBmih->biClrUsed != 0) ?
                        pSrcBmih->biClrUsed : (1 << pSrcBmih->biBitCount);
                    break;
                case 16:
                case 24:
                case 32:
                    nColorEntries = pSrcBmih->biClrUsed;
                    // If biBitCount is 16 or 32 and biCompression is
                    // BI_BITFIELDS the color table will be prefixed with
                    // three DWORD color masks.
                    if (pSrcBmih->biCompression == BI_BITFIELDS &&
                        (pSrcBmih->biBitCount == 16 ||
                         pSrcBmih->biBitCount == 32)) {
                        nColorEntries += 3;
                    }
                    break;
                default:
                    // The header is probably corrupted.
                    // Fail immediatelly to avoid memory access violation.
                    free(bBytes);
                    ::DeleteDC(hdc);
                    return NULL;
                }

                pSrcBits = (LPSTR)pSrcBmi + pSrcBmih->biSize
                    + nColorEntries * sizeof(RGBQUAD);
            }
            break;
        case CF_ENHMETAFILE:
        case CF_METAFILEPICT:
            lpEnhMetaFileBits = (BYTE*)bBytes + uOffset;
            // Warning C4244. size is jsize, uOffset is SIZE_T.
            // We assert that size > uOffset, so it is safe to cast to jsize.
            hEnhMetaFile = ::SetEnhMetaFileBits(size - (jsize)uOffset,
                                                lpEnhMetaFileBits);
            DASSERT(hEnhMetaFile != NULL);

            {
                UINT uHeaderSize =
                    ::GetEnhMetaFileHeader(hEnhMetaFile, 0, NULL);
                DASSERT(uHeaderSize != 0);
                ENHMETAHEADER* lpemh = (ENHMETAHEADER*)safe_Malloc(uHeaderSize);
                VERIFY(::GetEnhMetaFileHeader(hEnhMetaFile, uHeaderSize,
                                              lpemh) == uHeaderSize);
                LPRECTL lpFrame = &lpemh->rclFrame;
                POINT p = { abs(lpFrame->right - lpFrame->left),
                            abs(lpFrame->bottom - lpFrame->top) };
                VERIFY(::SaveDC(hdc));
                VERIFY(::SetMapMode(hdc, MM_HIMETRIC));
                VERIFY(::LPtoDP(hdc, &p, 1));
                VERIFY(::RestoreDC(hdc, -1));
                width = p.x;
                height = -p.y;

                free(lpemh);
            }
            break;
        default:
            DASSERT(FALSE); // Other formats are not supported yet.
            free(bBytes);
            ::DeleteDC(hdc);
            return NULL;
        }

        // JNI doesn't allow to store more than INT_MAX in a single array.
        // We report conversion failure in this case.
        if (width * height > INT_MAX) {
            free(bBytes);
            ::DeleteDC(hdc);
            return NULL;
        }

        numPixels = width * height;

        if (pLogPalette != NULL) {
            hPalette = ::CreatePalette(pLogPalette);
            if (hPalette == NULL) {
                free(bBytes);
                ::DeleteDC(hdc);
                return NULL;
            }
            hOldPalette = ::SelectPalette(hdc, hPalette, FALSE);
            ::RealizePalette(hdc);
        }

        // allocate memory for BITMAPINFO
        pDstBmi = (BITMAPINFO *)safe_Calloc(1, sizeof(BITMAPINFO));
        pDstBmih = &pDstBmi->bmiHeader;

        static const int BITS_PER_PIXEL = 32;

        // prepare BITMAPINFO for a 32-bit RGB bitmap
        pDstBmih->biSize = sizeof(BITMAPINFOHEADER);
        pDstBmih->biWidth = width;
        pDstBmih->biHeight = -height; // negative height means a top-down DIB
        pDstBmih->biPlanes = 1;
        pDstBmih->biBitCount = BITS_PER_PIXEL;
        pDstBmih->biCompression = BI_RGB;
        // NOTE: MSDN says that biSizeImage may be set to 0 for BI_RGB bitmaps,
        // but this causes CreateDIBSection to allocate zero-size memory block
        // for DIB data. It works okay when biSizeImage is explicitly specified.
        pDstBmih->biSizeImage = width * height * (BITS_PER_PIXEL >> 3);

        hDibSection = ::CreateDIBSection(hdc, (BITMAPINFO*)pDstBmi,
                                         DIB_RGB_COLORS, &pDstBits,
                                         NULL, 0);

        if (hDibSection == NULL) {
            free(pDstBmi); pDstBmi = NULL;
            if (hPalette != NULL) {
                VERIFY(::SelectPalette(hdc, hOldPalette, FALSE) != NULL);
                hOldPalette = NULL;
                VERIFY(::DeleteObject(hPalette)); hPalette = NULL;
            }
            VERIFY(::DeleteDC(hdc)); hdc = NULL;
            free(bBytes); bBytes = NULL;

            JNU_ThrowIOException(env, "failed to get drop data");
            return NULL;
        }

        hOldBitmap = (HBITMAP)::SelectObject(hdc, hDibSection);
        DASSERT(hOldBitmap != NULL);

        switch (format) {
        case CF_DIB:
            VERIFY(::StretchDIBits(hdc,
                                   0, 0, width, height,
                                   0, 0, width, height,
                                   pSrcBits, pSrcBmi,
                                   DIB_RGB_COLORS, SRCCOPY) != GDI_ERROR);
            break;
        case CF_ENHMETAFILE:
        case CF_METAFILEPICT: {
            RECT rect = { 0, 0, width, height };

            VERIFY(::PlayEnhMetaFile(hdc, hEnhMetaFile, &rect));
            VERIFY(::DeleteEnhMetaFile(hEnhMetaFile)); hEnhMetaFile = NULL;
            break;
        }
        default:
            // Other formats are not supported yet.
            DASSERT(FALSE);
            break;
        }

        // convert Win32 pixel format (BGRX) to Java format (ARGB)
        DASSERT(sizeof(jint) == sizeof(RGBQUAD));
        RGBQUAD* prgbq = (RGBQUAD*)pDstBits;
        for(int nPixel = 0; nPixel < numPixels; nPixel++, prgbq++) {
            jint jpixel = WIN_TO_JAVA_PIXEL(prgbq->rgbRed,
                                            prgbq->rgbGreen,
                                            prgbq->rgbBlue);
            // stuff the 32-bit pixel back into the 32-bit RGBQUAD
            *prgbq = *((RGBQUAD*)(&jpixel));
        }

        buffer = env->NewIntArray(numPixels + 2);
        if (buffer == NULL) {
            throw std::bad_alloc();
        }

        // copy pixels into Java array
        env->SetIntArrayRegion(buffer, 0, numPixels, (jint*)pDstBits);

        // copy dimensions into Java array
        env->SetIntArrayRegion(buffer, numPixels, 1, (jint*)&width);
        env->SetIntArrayRegion(buffer, numPixels + 1, 1, (jint*)&height);

        VERIFY(::SelectObject(hdc, hOldBitmap) != NULL); hOldBitmap = NULL;
        VERIFY(::DeleteObject(hDibSection)); hDibSection = NULL;
        free(pDstBmi); pDstBmi = NULL;
        if (hPalette != NULL) {
            VERIFY(::SelectPalette(hdc, hOldPalette, FALSE) != NULL);
            hOldPalette = NULL;
            VERIFY(::DeleteObject(hPalette)); hPalette = NULL;
        }
        VERIFY(::DeleteDC(hdc)); hdc = NULL;
        free(bBytes); bBytes = NULL;
    } catch (...) {
        if (hdc != NULL && hOldBitmap != NULL) {
            VERIFY(::SelectObject(hdc, hOldBitmap) != NULL); hOldBitmap = NULL;
        }
        if (hDibSection != NULL) {
            VERIFY(::DeleteObject(hDibSection)); hDibSection = NULL;
        }
        if (pDstBmi != NULL) {
            free(pDstBmi); pDstBmi = NULL;
        }
        if (hPalette != NULL) {
            if (hdc != NULL) {
                VERIFY(::SelectPalette(hdc, hOldPalette, FALSE) != NULL);
                hOldPalette = NULL;
            }
            VERIFY(::DeleteObject(hPalette)); hPalette = NULL;
        }
        if (hdc != NULL) {
            VERIFY(::DeleteDC(hdc)); hdc = NULL;
        }
        if (hEnhMetaFile != NULL) {
            VERIFY(::DeleteEnhMetaFile(hEnhMetaFile)); hEnhMetaFile = NULL;
        }
        if (bBytes != NULL) {
            free(bBytes); bBytes = NULL;
        }
        throw;
    }

    return buffer;

    CATCH_BAD_ALLOC_RET(NULL);
}

/*
 * Class:     sun_awt_windows_WDataTransferer
 * Method:    imageDataToPlatformImageBytes
 * Signature: ([BIII)[B
 */
JNIEXPORT jbyteArray JNICALL
Java_sun_awt_windows_WDataTransferer_imageDataToPlatformImageBytes(JNIEnv *env,
                                               jobject self, jbyteArray imageData,
                                               jint width, jint height,
                                               jlong format) {

    TRY;

    if (JNU_IsNull(env, imageData)) {
        return NULL;
    }

    UINT size = env->GetArrayLength(imageData);
    if (size == 0) {
        return NULL;
    }

    // In the passed imageData array all lines are padded with zeroes except for
    // the last one, so we have to add one pad size here.
    int mod = (width * 3) % 4;
    int pad = mod > 0 ? 4 - mod : 0;
    int nBytes = sizeof(BITMAPINFO) + size + pad;
    BITMAPINFO* pinfo = (BITMAPINFO*)safe_Calloc(1, nBytes);

    static const int BITS_PER_PIXEL = 24;

    // prepare BITMAPINFO for a 24-bit BGR bitmap
    pinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pinfo->bmiHeader.biWidth = width;
    pinfo->bmiHeader.biHeight = height; // positive height means a bottom-up DIB
    pinfo->bmiHeader.biPlanes = 1;
    pinfo->bmiHeader.biBitCount = BITS_PER_PIXEL;
    pinfo->bmiHeader.biCompression = BI_RGB;
    // NOTE: MSDN says that biSizeImage may be set to 0 for BI_RGB bitmaps,
    // but some programs (e.g. Imaging for Windows NT by Wang Laboratories)
    // don't handle such DIBs correctly, so we specify the size explicitly.
    pinfo->bmiHeader.biSizeImage = size + pad;

    jbyte *array = (jbyte*)((LPSTR)pinfo + sizeof(BITMAPINFOHEADER));
    env->GetByteArrayRegion(imageData, 0, size, array);
    HRESULT hr = S_OK;

    jbyteArray bytes = NULL;
    switch (format) {
    case CF_DIB:
        bytes = env->NewByteArray(nBytes);
        if( NULL == bytes ) {
            hr = E_OUTOFMEMORY;
        } else {
            env->SetByteArrayRegion(bytes, 0, nBytes, (jbyte*)pinfo);
        }
        break;
    case CF_ENHMETAFILE:
    {
        HDC hdc = ::GetDC(NULL);
        if( NULL == hdc) {
            hr = HRESULT_FROM_WIN32(::GetLastError());
        } else {
            POINT p = { width, height };
            //We are trying to support context-independent metafile.
            //To implement it we have to select correct MM_HIMETRIC map mode.
            VERIFY(::SetMapMode(hdc, MM_HIMETRIC));
            VERIFY(::DPtoLP(hdc, &p, 1));
            //In accordance with CreateEnhMetaFile documentation the rectangle have to
            //be normal (left <= right, top <= bottom)
            RECT r = { min(0, p.x), min(0, p.y), max(0, p.x), max(0, p.y) };
            //Due to inversed row order in source bitmap the destination
            //height have to be negative.
            HDC hemfdc = ::CreateEnhMetaFile(NULL, NULL, &r, NULL);
            if( NULL == hemfdc) {
                hr = HRESULT_FROM_WIN32(::GetLastError());
            } else {
                int iMFHeight = r.bottom - r.top;
                int iMFWidth = r.right - r.left;
                VERIFY(::SetMapMode(hemfdc, MM_HIMETRIC));
                if( GDI_ERROR == ::StretchDIBits(hemfdc,
                    0, iMFHeight, iMFWidth, -iMFHeight,
                    0, 0, width, height,
                    (LPVOID)array, pinfo,
                    DIB_RGB_COLORS, SRCCOPY))
                {
                    hr = HRESULT_FROM_WIN32(::GetLastError());
                }
                HENHMETAFILE hemf = ::CloseEnhMetaFile(hemfdc);
                if( NULL == hemf) {
                    hr = HRESULT_FROM_WIN32(::GetLastError());
                } else {
                    if(SUCCEEDED(hr)){
                        UINT uEmfSize = ::GetEnhMetaFileBits(hemf, 0, NULL);
                        if( 0 == uEmfSize) {
                            hr = HRESULT_FROM_WIN32(::GetLastError());
                        } else {
                            LPBYTE lpbEmfBuffer = NULL;
                            try {
                                lpbEmfBuffer = (LPBYTE)safe_Malloc(uEmfSize);
                                VERIFY(::GetEnhMetaFileBits(hemf, uEmfSize,
                                                            lpbEmfBuffer) == uEmfSize);
                                bytes = env->NewByteArray(uEmfSize);
                                if(NULL == bytes) {
                                    hr = E_OUTOFMEMORY;
                                } else {
                                    env->SetByteArrayRegion(bytes, 0, uEmfSize, (jbyte*)lpbEmfBuffer);
                                }
                            } catch (std::bad_alloc &) {
                                hr = E_OUTOFMEMORY;
                            }
                            free(lpbEmfBuffer);
                        }
                    }
                    VERIFY(::DeleteEnhMetaFile(hemf));
                }
            }
            VERIFY(::ReleaseDC(NULL, hdc));
        }
        break;
    }
    case CF_METAFILEPICT:
    {
        HDC hdc = ::GetDC(NULL);
        if( NULL == hdc) {
            hr = HRESULT_FROM_WIN32(::GetLastError());
        } else {
            POINT p = { width, height };
            VERIFY(::SetMapMode(hdc, MM_HIMETRIC));
            VERIFY(::DPtoLP(hdc, &p, 1));
            RECT r = { min(0, p.x), min(0, p.y), max(0, p.x), max(0, p.y) };
            HDC hmfdc = ::CreateMetaFile(NULL);
            if( NULL == hmfdc) {
                hr = HRESULT_FROM_WIN32(::GetLastError());
            } else {
                VERIFY(::SetMapMode(hmfdc, MM_HIMETRIC));
                int iMFHeight = r.bottom - r.top;
                int iMFWidth = r.right - r.left;
                //The destination Y coordinate (3d parameter in StretchDIBits call) is different for
                //CF_ENHMETAFILE and CF_METAFILEPICT formats due to applying MM_ANISOTROPIC map mode
                //at very last moment. MM_ANISOTROPIC map mode changes the Y-axis direction and can be
                //selected just for metafile header.
                if( GDI_ERROR == ::StretchDIBits(hmfdc,
                    0, 0, iMFWidth, -iMFHeight,
                    0, 0, width, height,
                    (LPVOID)array, pinfo,
                    DIB_RGB_COLORS, SRCCOPY))
                {
                    hr = HRESULT_FROM_WIN32(::GetLastError());
                }
                HMETAFILE hmf = ::CloseMetaFile(hmfdc);
                if( NULL == hmf) {
                    hr = HRESULT_FROM_WIN32(::GetLastError());
                } else {
                    if(SUCCEEDED(hr)){
                        UINT uMfSize = ::GetMetaFileBitsEx(hmf, 0, NULL);
                        if( 0 == uMfSize) {
                            hr = HRESULT_FROM_WIN32(::GetLastError());
                        } else {
                            LPBYTE lpbMfBuffer = NULL;
                            try {
                                lpbMfBuffer = (LPBYTE)SAFE_SIZE_STRUCT_ALLOC(safe_Malloc,
                                        sizeof(METAFILEPICT), uMfSize, 1);
                                const UINT uMfSizeWithHead = uMfSize + sizeof(METAFILEPICT);
                                VERIFY(::GetMetaFileBitsEx(hmf, uMfSize,
                                                            lpbMfBuffer + sizeof(METAFILEPICT)) == uMfSize);
                                bytes = env->NewByteArray(uMfSizeWithHead);
                                if(NULL == bytes) {
                                    hr = E_OUTOFMEMORY;
                                } else {
                                    LPMETAFILEPICT lpMfp = (LPMETAFILEPICT)lpbMfBuffer;
                                    lpMfp->mm = MM_ANISOTROPIC; // should use MM_ANISOTROPIC exactly (MSDN)
                                    lpMfp->xExt = iMFWidth;
                                    lpMfp->yExt = iMFHeight;
                                    env->SetByteArrayRegion(bytes, 0, uMfSizeWithHead, (jbyte*)lpbMfBuffer);
                                }
                            } catch (std::bad_alloc &) {
                                hr = E_OUTOFMEMORY;
                            }
                            free(lpbMfBuffer);
                        }
                    }
                    VERIFY(::DeleteMetaFile(hmf));
                }
            }
            VERIFY(::ReleaseDC(NULL, hdc));
        }
        break;
    }
    default:
        DASSERT(FALSE); // Other formats are not supported yet.
        hr = E_NOTIMPL;
        break;
    }
    free(pinfo);
    if(FAILED(hr)){
        if(E_OUTOFMEMORY == hr)
            throw std::bad_alloc();
        return NULL;
    }
    return bytes;
    CATCH_BAD_ALLOC_RET(NULL);
}

/*
 * Class:     sun_awt_windows_WDataTransferer
 * Method:    registerClipboardFormat
 * Signature: (Ljava/lang/String;)J
 */
JNIEXPORT jlong JNICALL
Java_sun_awt_windows_WDataTransferer_registerClipboardFormat(JNIEnv *env,
                                                             jclass cls,
                                                             jstring str)
{
    TRY;

    LPCTSTR cStr = JNU_GetStringPlatformChars(env, str, NULL);
    jlong value = ::RegisterClipboardFormat(cStr);
    JNU_ReleaseStringPlatformChars(env, str, cStr);

    return value;

    CATCH_BAD_ALLOC_RET(0);
}

/*
 * Class:     sun_awt_windows_WDataTransferer
 * Method:    getClipboardFormatName
 * Signature: (J)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL
Java_sun_awt_windows_WDataTransferer_getClipboardFormatName(JNIEnv *env,
                                                            jclass cls,
                                                            jlong format)
{
    TRY;

    LPTSTR buf = new TCHAR[512]; // perhaps a bad idea to limit ourselves to 512
    VERIFY(::GetClipboardFormatName((UINT)format, buf, 512));
    jstring name = JNU_NewStringPlatform(env, buf);
    delete [] buf;
    if (name == NULL) {
        throw std::bad_alloc();
    }
    return name;

    CATCH_BAD_ALLOC_RET(NULL);
}

/*
 * Class:     sun_awt_windows_WToolkitThreadBlockedHandler
 * Method:    startSecondaryEventLoop
 * Signature: ()V;
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WToolkitThreadBlockedHandler_startSecondaryEventLoop(JNIEnv *env, jclass)
{
    TRY;

    AwtDataTransferer::SecondaryMessageLoop();

    CATCH_BAD_ALLOC;
}

}

Other Java examples (source code examples)

Here is a short list of links related to this Java awt_DataTransferer.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.