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