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