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