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