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