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