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 44extern "C" { 45 DWORD __cdecl convertActionsToDROPEFFECT(jint actions); 46 jint __cdecl convertDROPEFFECTToActions(DWORD effects); 47 DWORD __cdecl mapModsToDROPEFFECT(DWORD, DWORD); 48} // extern "C" 49 50 51IDataObject* AwtDropTarget::sm_pCurrentDnDDataObject = (IDataObject*)NULL; 52 53/** 54 * constructor 55 */ 56 57AwtDropTarget::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 77AwtDropTarget::~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 98HRESULT __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 114ULONG __stdcall AwtDropTarget::AddRef() { 115 return (ULONG)++m_refs; 116} 117 118/** 119 * Release 120 */ 121 122ULONG __stdcall AwtDropTarget::Release() { 123 int refs; 124 125 if ((refs = --m_refs) == 0) delete this; 126 127 return (ULONG)refs; 128} 129 130void 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 144HRESULT __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 223HRESULT __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 280HRESULT __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 321HRESULT __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 397void 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 407void 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 417void 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 427void AwtDropTarget::_RegisterTarget(void* param) { 428 RegisterTargetPtr rtrp = (RegisterTargetPtr)param; 429 430 rtrp->dropTarget->RegisterTarget(rtrp->show); 431} 432 433/** 434 * RegisterTarget 435 */ 436 437void 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 477jobject 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 494void 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 509HRESULT 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 555HRESULT 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 567jobject 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 807HRESULT 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 842HRESULT 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 897jobject 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 969jobject 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 1000int __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 1011const unsigned int AwtDropTarget::CACHE_INCR = 16; 1012 1013void 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 1101void 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 1133void AwtDropTarget::DragCleanup(void) { 1134 UnloadCache(); 1135} 1136 1137BOOL 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 1173DECLARE_JAVA_CLASS(dTCClazz, "sun/awt/windows/WDropTargetContextPeer") 1174 1175jobject 1176AwtDropTarget::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 1183jint 1184AwtDropTarget::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 1194void 1195AwtDropTarget::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 1202jint 1203AwtDropTarget::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 1213void 1214AwtDropTarget::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 1224jobject 1225AwtDropTarget::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 1231jobject 1232AwtDropTarget::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 1244WDTCPIStreamWrapper::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 1257WDTCPIStreamWrapper::~WDTCPIStreamWrapper() { 1258 ::CloseHandle(m_mutex); 1259 m_istream->Release(); 1260 ::ReleaseStgMedium(&m_stgmedium); 1261} 1262 1263/** 1264 * return available data 1265 */ 1266 1267jint 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 1283void 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 1295jint 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 1315jint 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 1331void 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 1343jint 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 1366jint 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 1382void 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 1396jint 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 1425void WDTCPIStreamWrapper::DoClose(WDTCPIStreamWrapper* istream) { 1426 AwtToolkit::GetInstance().InvokeFunctionLater(_Close, istream); 1427} 1428 1429/** 1430 * close 1431 */ 1432 1433void WDTCPIStreamWrapper::_Close(void* param) { 1434 ((WDTCPIStreamWrapper*)param)->Close(); 1435} 1436 1437/** 1438 * close 1439 */ 1440 1441void WDTCPIStreamWrapper::Close() { 1442 delete this; 1443} 1444 1445/*****************************************************************************/ 1446 1447extern "C" { 1448 1449/** 1450 * awt_dnd_initialize: initial DnD system 1451 */ 1452 1453void awt_dnd_initialize() { 1454 ::OleInitialize((LPVOID)NULL); 1455} 1456 1457/** 1458 * awt_dnd_uninitialize: deactivate DnD system 1459 */ 1460 1461void awt_dnd_uninitialize() { 1462 ::OleUninitialize(); 1463} 1464 1465/** 1466 * convertActionsToDROPEFFECT 1467 */ 1468 1469DWORD 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 1482jint 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 1496DWORD 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 1541JNIEXPORT 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 1556JNIEXPORT void JNICALL 1557Java_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 1573JNIEXPORT 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 1587JNIEXPORT 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 1599JNIEXPORT 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 1611JNIEXPORT 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 1623JNIEXPORT 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" */ 1632