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" */