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