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