1 /*******************************************************************************
2 * Copyright (c) 2000, 2017 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.dnd;
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.internal.*;
19 import org.eclipse.swt.internal.ole.win32.*;
20 import org.eclipse.swt.internal.win32.*;
21 import org.eclipse.swt.widgets.*;
24 * The <code>Clipboard</code> provides a mechanism for transferring data from one
25 * application to another or within an application.
27 * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
29 * @see <a href="http://www.eclipse.org/swt/snippets/#clipboard">Clipboard snippets</a>
30 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ClipboardExample</a>
31 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
32 * @noextend This class is not intended to be subclassed by clients.
34 public class Clipboard {
36 private static final int RETRY_LIMIT = 10;
37 private Display display;
40 private COMObject iDataObject;
42 private Transfer[] transferAgents = new Transfer[0];
43 private Object[] data = new Object[0];
44 private int CFSTR_PREFERREDDROPEFFECT;
47 * Constructs a new instance of this class. Creating an instance of a Clipboard
48 * may cause system resources to be allocated depending on the platform. It is therefore
49 * mandatory that the Clipboard instance be disposed when no longer required.
51 * @param display the display on which to allocate the clipboard
53 * @exception SWTException <ul>
54 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
55 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
58 * @see Clipboard#dispose
59 * @see Clipboard#checkSubclass
61 public Clipboard(Display display) {
63 if (display == null) {
64 display = Display.getCurrent();
65 if (display == null) {
66 display = Display.getDefault();
69 if (display.getThread() != Thread.currentThread()) {
70 DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
72 this.display = display;
73 TCHAR chFormatName = new TCHAR(0, "Preferred DropEffect", true); //$NON-NLS-1$
74 CFSTR_PREFERREDDROPEFFECT = OS.RegisterClipboardFormat(chFormatName);
75 createCOMInterfaces();
80 * Checks that this class can be subclassed.
82 * The SWT class library is intended to be subclassed
83 * only at specific, controlled points. This method enforces this
84 * rule unless it is overridden.
86 * <em>IMPORTANT:</em> By providing an implementation of this
87 * method that allows a subclass of a class which does not
88 * normally allow subclassing to be created, the implementer
89 * agrees to be fully responsible for the fact that any such
90 * subclass will likely fail between SWT releases and will be
91 * strongly platform specific. No support is provided for
92 * user-written classes which are implemented in this fashion.
94 * The ability to subclass outside of the allowed SWT classes
95 * is intended purely to enable those not on the SWT development
96 * team to implement patches in order to get around specific
97 * limitations in advance of when those limitations can be
98 * addressed by the team. Subclassing should not be attempted
99 * without an intimate and detailed understanding of the hierarchy.
102 * @exception SWTException <ul>
103 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
106 protected void checkSubclass () {
107 String name = getClass().getName ();
108 String validName = Clipboard.class.getName();
109 if (!validName.equals(name)) {
110 DND.error (SWT.ERROR_INVALID_SUBCLASS);
115 * Throws an <code>SWTException</code> if the receiver can not
116 * be accessed by the caller. This may include both checks on
117 * the state of the receiver and more generally on the entire
118 * execution context. This method <em>should</em> be called by
119 * widget implementors to enforce the standard SWT invariants.
121 * Currently, it is an error to invoke any method (other than
122 * <code>isDisposed()</code>) on a widget that has had its
123 * <code>dispose()</code> method called. It is also an error
124 * to call widget methods from any thread that is different
125 * from the thread that created the widget.
127 * In future releases of SWT, there may be more or fewer error
128 * checks and exceptions may be thrown for different reasons.
131 * @exception SWTException <ul>
132 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
133 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
136 protected void checkWidget () {
137 Display display = this.display;
138 if (display == null) DND.error (SWT.ERROR_WIDGET_DISPOSED);
139 if (display.getThread() != Thread.currentThread ()) DND.error (SWT.ERROR_THREAD_INVALID_ACCESS);
140 if (display.isDisposed()) DND.error(SWT.ERROR_WIDGET_DISPOSED);
144 * If this clipboard is currently the owner of the data on the system clipboard,
145 * clear the contents. If this clipboard is not the owner, then nothing is done.
146 * Note that there are clipboard assistant applications that take ownership of
147 * data or make copies of data when it is placed on the clipboard. In these
148 * cases, it may not be possible to clear the clipboard.
150 * @exception SWTException <ul>
151 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
152 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
157 public void clearContents() {
158 clearContents(DND.CLIPBOARD);
162 * If this clipboard is currently the owner of the data on the specified
163 * clipboard, clear the contents. If this clipboard is not the owner, then
166 * <p>Note that there are clipboard assistant applications that take ownership
167 * of data or make copies of data when it is placed on the clipboard. In these
168 * cases, it may not be possible to clear the clipboard.</p>
170 * <p>The clipboards value is either one of the clipboard constants defined in
171 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
172 * (that is, using the <code>int</code> "|" operator) two or more
173 * of those <code>DND</code> clipboard constants.</p>
175 * @param clipboards to be cleared
177 * @exception SWTException <ul>
178 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
179 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
183 * @see DND#SELECTION_CLIPBOARD
187 public void clearContents(int clipboards) {
189 if ((clipboards & DND.CLIPBOARD) != 0) {
190 /* OleIsCurrentClipboard([in] pDataObject)
191 * The argument pDataObject is owned by the caller so reference count does not
192 * need to be incremented.
194 if (COM.OleIsCurrentClipboard(this.iDataObject.getAddress()) == COM.S_OK) {
195 /* OleSetClipboard([in] pDataObject)
196 * The argument pDataObject is owned by the caller so reference count does not
197 * need to be incremented.
199 COM.OleSetClipboard(0);
205 * Disposes of the operating system resources associated with the clipboard.
206 * The data will still be available on the system clipboard after the dispose
209 * <p>NOTE: On some platforms the data will not be available once the application
210 * has exited or the display has been disposed.</p>
212 * @exception SWTException <ul>
213 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
216 public void dispose () {
217 if (isDisposed()) return;
218 if (display.getThread() != Thread.currentThread()) DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
219 /* OleIsCurrentClipboard([in] pDataObject)
220 * The argument pDataObject is owned by the caller so reference count does not
221 * need to be incremented.
223 if (COM.OleIsCurrentClipboard(this.iDataObject.getAddress()) == COM.S_OK) {
224 COM.OleFlushClipboard();
231 * Retrieve the data of the specified type currently available on the system
232 * clipboard. Refer to the specific subclass of <code>Transfer</code> to
233 * determine the type of object returned.
235 * <p>The following snippet shows text and RTF text being retrieved from the
239 * Clipboard clipboard = new Clipboard(display);
240 * TextTransfer textTransfer = TextTransfer.getInstance();
241 * String textData = (String)clipboard.getContents(textTransfer);
242 * if (textData != null) System.out.println("Text is "+textData);
243 * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
244 * String rtfData = (String)clipboard.getContents(rtfTransfer);
245 * if (rtfData != null) System.out.println("RTF Text is "+rtfData);
246 * clipboard.dispose();
249 * @param transfer the transfer agent for the type of data being requested
250 * @return the data obtained from the clipboard or null if no data of this type is available
252 * @exception SWTException <ul>
253 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
254 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
256 * @exception IllegalArgumentException <ul>
257 * <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
262 public Object getContents(Transfer transfer) {
263 return getContents(transfer, DND.CLIPBOARD);
266 * Retrieve the data of the specified type currently available on the specified
267 * clipboard. Refer to the specific subclass of <code>Transfer</code> to
268 * determine the type of object returned.
270 * <p>The following snippet shows text and RTF text being retrieved from the
274 * Clipboard clipboard = new Clipboard(display);
275 * TextTransfer textTransfer = TextTransfer.getInstance();
276 * String textData = (String)clipboard.getContents(textTransfer);
277 * if (textData != null) System.out.println("Text is "+textData);
278 * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
279 * String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD);
280 * if (rtfData != null) System.out.println("RTF Text is "+rtfData);
281 * clipboard.dispose();
284 * <p>The clipboards value is either one of the clipboard constants defined in
285 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
286 * (that is, using the <code>int</code> "|" operator) two or more
287 * of those <code>DND</code> clipboard constants.</p>
289 * @param transfer the transfer agent for the type of data being requested
290 * @param clipboards on which to look for data
292 * @return the data obtained from the clipboard or null if no data of this type is available
294 * @exception SWTException <ul>
295 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
296 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
298 * @exception IllegalArgumentException <ul>
299 * <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
304 * @see DND#SELECTION_CLIPBOARD
308 public Object getContents(Transfer transfer, int clipboards) {
310 if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
311 if ((clipboards & DND.CLIPBOARD) == 0) return null;
313 * Bug in Windows. When a new application takes control
314 * of the clipboard, other applications may open the
315 * clipboard to determine if they want to record the
316 * clipboard updates. When this happens, the clipboard
317 * can not be accessed until the other application is
318 * finished. To allow the other applications to release
319 * the clipboard, use PeekMessage() to enable cross thread
322 long[] ppv = new long[1];
324 /* OleGetClipboard([out] ppDataObject).
325 * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
327 int result = COM.OleGetClipboard(ppv);
328 while (result != COM.S_OK && retryCount++ < RETRY_LIMIT) {
329 try {Thread.sleep(50);} catch (Throwable t) {}
331 OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
332 result = COM.OleGetClipboard(ppv);
334 if (result != COM.S_OK) return null;
335 IDataObject dataObject = new IDataObject(ppv[0]);
337 TransferData[] allowed = transfer.getSupportedTypes();
338 for (int i = 0; i < allowed.length; i++) {
339 if (dataObject.QueryGetData(allowed[i].formatetc) == COM.S_OK) {
340 TransferData data = allowed[i];
341 data.pIDataObject = ppv[0];
342 return transfer.nativeToJava(data);
346 dataObject.Release();
348 return null; // No data available for this transfer
351 * Returns <code>true</code> if the clipboard has been disposed,
352 * and <code>false</code> otherwise.
354 * This method gets the dispose state for the clipboard.
355 * When a clipboard has been disposed, it is an error to
356 * invoke any other method using the clipboard.
359 * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
363 public boolean isDisposed () {
364 return (display == null);
368 * Place data of the specified type on the system clipboard. More than one type
369 * of data can be placed on the system clipboard at the same time. Setting the
370 * data clears any previous data from the system clipboard, regardless of type.
372 * <p>NOTE: On some platforms, the data is immediately copied to the system
373 * clipboard but on other platforms it is provided upon request. As a result,
374 * if the application modifies the data object it has set on the clipboard, that
375 * modification may or may not be available when the data is subsequently
378 * <p>The following snippet shows text and RTF text being set on the copy/paste
383 * Clipboard clipboard = new Clipboard(display);
384 * String textData = "Hello World";
385 * String rtfData = "{\\rtf1\\b\\i Hello World}";
386 * TextTransfer textTransfer = TextTransfer.getInstance();
387 * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
388 * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
389 * Object[] data = new Object[]{textData, rtfData};
390 * clipboard.setContents(data, transfers);
391 * clipboard.dispose();
394 * @param data the data to be set in the clipboard
395 * @param dataTypes the transfer agents that will convert the data to its
396 * platform specific format; each entry in the data array must have a
397 * corresponding dataType
399 * @exception IllegalArgumentException <ul>
400 * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
401 * or the length of data is not the same as the length of dataTypes</li>
403 * @exception SWTException <ul>
404 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
405 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
407 * @exception SWTError <ul>
408 * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
411 * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
412 * recoverable error, but can not be changed due to backward compatibility.</p>
414 public void setContents(Object[] data, Transfer[] dataTypes) {
415 setContents(data, dataTypes, DND.CLIPBOARD);
419 * Place data of the specified type on the specified clipboard. More than one
420 * type of data can be placed on the specified clipboard at the same time.
421 * Setting the data clears any previous data from the specified
422 * clipboard, regardless of type.
424 * <p>NOTE: On some platforms, the data is immediately copied to the specified
425 * clipboard but on other platforms it is provided upon request. As a result,
426 * if the application modifies the data object it has set on the clipboard, that
427 * modification may or may not be available when the data is subsequently
430 * <p>The clipboards value is either one of the clipboard constants defined in
431 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
432 * (that is, using the <code>int</code> "|" operator) two or more
433 * of those <code>DND</code> clipboard constants.</p>
435 * <p>The following snippet shows text and RTF text being set on the copy/paste
440 * Clipboard clipboard = new Clipboard(display);
441 * String textData = "Hello World";
442 * String rtfData = "{\\rtf1\\b\\i Hello World}";
443 * TextTransfer textTransfer = TextTransfer.getInstance();
444 * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
445 * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
446 * Object[] data = new Object[]{textData, rtfData};
447 * clipboard.setContents(data, transfers, DND.CLIPBOARD);
448 * clipboard.dispose();
451 * @param data the data to be set in the clipboard
452 * @param dataTypes the transfer agents that will convert the data to its
453 * platform specific format; each entry in the data array must have a
454 * corresponding dataType
455 * @param clipboards on which to set the data
457 * @exception IllegalArgumentException <ul>
458 * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
459 * or the length of data is not the same as the length of dataTypes</li>
461 * @exception SWTException <ul>
462 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
463 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
465 * @exception SWTError <ul>
466 * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
469 * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
470 * recoverable error, but can not be changed due to backward compatibility.</p>
473 * @see DND#SELECTION_CLIPBOARD
477 public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) {
479 if (data == null || dataTypes == null || data.length != dataTypes.length || data.length == 0) {
480 DND.error(SWT.ERROR_INVALID_ARGUMENT);
482 for (int i = 0; i < data.length; i++) {
483 if (data[i] == null || dataTypes[i] == null || !dataTypes[i].validate(data[i])) {
484 DND.error(SWT.ERROR_INVALID_ARGUMENT);
487 if ((clipboards & DND.CLIPBOARD) == 0) return;
489 this.transferAgents = dataTypes;
490 /* OleSetClipboard([in] pDataObject)
491 * The argument pDataObject is owned by the caller so the reference count does not
492 * need to be incremented.
494 int result = COM.OleSetClipboard(iDataObject.getAddress());
497 * Bug in Windows. When a new application takes control
498 * of the clipboard, other applications may open the
499 * clipboard to determine if they want to record the
500 * clipboard updates. When this happens, the clipboard
501 * can not be flushed until the other application is
502 * finished. To allow other applications to get the
503 * data, use PeekMessage() to enable cross thread
507 while (result != COM.S_OK && retryCount++ < RETRY_LIMIT) {
508 try {Thread.sleep(50);} catch (Throwable t) {}
510 OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
511 result = COM.OleSetClipboard(iDataObject.getAddress());
513 if (result != COM.S_OK) {
514 DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
517 private int AddRef() {
521 private void createCOMInterfaces() {
522 // register each of the interfaces that this object implements
523 iDataObject = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 2, 3, 2, 4, 1, 1}){
525 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
527 public long method1(long[] args) {return AddRef();}
529 public long method2(long[] args) {return Release();}
531 public long method3(long[] args) {return GetData(args[0], args[1]);}
532 // method4 GetDataHere - not implemented
534 public long method5(long[] args) {return QueryGetData(args[0]);}
535 // method6 GetCanonicalFormatEtc - not implemented
536 // method7 SetData - not implemented
538 public long method8(long[] args) {return EnumFormatEtc((int)args[0], args[1]);}
539 // method9 DAdvise - not implemented
540 // method10 DUnadvise - not implemented
541 // method11 EnumDAdvise - not implemented
544 private void disposeCOMInterfaces() {
545 if (iDataObject != null)
546 iDataObject.dispose();
550 * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
551 * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
552 * must be incremented before returning. Caller is responsible for releasing ppenumFormatetc.
554 private int EnumFormatEtc(int dwDirection, long ppenumFormatetc) {
555 // only allow getting of data - SetData is not currently supported
556 if (dwDirection == COM.DATADIR_SET) return COM.E_NOTIMPL;
557 // what types have been registered?
558 TransferData[] allowedDataTypes = new TransferData[0];
559 for (int i = 0; i < transferAgents.length; i++){
560 TransferData[] formats = transferAgents[i].getSupportedTypes();
561 TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
562 System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
563 System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
564 allowedDataTypes = newAllowedDataTypes;
566 OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
567 enumFORMATETC.AddRef();
568 FORMATETC[] formats = new FORMATETC[allowedDataTypes.length + 1];
569 for (int i = 0; i < allowedDataTypes.length; i++){
570 formats[i] = allowedDataTypes[i].formatetc;
572 // include the drop effect format to specify a copy operation
573 FORMATETC dropeffect = new FORMATETC();
574 dropeffect.cfFormat = CFSTR_PREFERREDDROPEFFECT;
575 dropeffect.dwAspect = COM.DVASPECT_CONTENT;
576 dropeffect.lindex = -1;
577 dropeffect.tymed = COM.TYMED_HGLOBAL;
578 formats[formats.length -1] = dropeffect;
579 enumFORMATETC.setFormats(formats);
580 OS.MoveMemory(ppenumFormatetc, new long[] {enumFORMATETC.getAddress()}, C.PTR_SIZEOF);
583 private int GetData(long pFormatetc, long pmedium) {
584 /* Called by a data consumer to obtain data from a source data object.
585 The GetData method renders the data described in the specified FORMATETC
586 structure and transfers it through the specified STGMEDIUM structure.
587 The caller then assumes responsibility for releasing the STGMEDIUM structure.
589 if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
590 if (QueryGetData(pFormatetc) != COM.S_OK) return COM.DV_E_FORMATETC;
592 TransferData transferData = new TransferData();
593 transferData.formatetc = new FORMATETC();
594 COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
595 transferData.type = transferData.formatetc.cfFormat;
596 transferData.stgmedium = new STGMEDIUM();
597 transferData.result = COM.E_FAIL;
599 if (transferData.type == CFSTR_PREFERREDDROPEFFECT) {
600 // specify that a copy operation is to be performed
601 STGMEDIUM stgmedium = new STGMEDIUM();
602 stgmedium.tymed = COM.TYMED_HGLOBAL;
603 stgmedium.unionField = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, 4);
604 //TODO - should call GlobalLock
605 OS.MoveMemory(stgmedium.unionField, new int[] {COM.DROPEFFECT_COPY}, 4);
606 stgmedium.pUnkForRelease = 0;
607 COM.MoveMemory(pmedium, stgmedium, STGMEDIUM.sizeof);
611 // get matching transfer agent to perform conversion
612 int transferIndex = -1;
613 for (int i = 0; i < transferAgents.length; i++){
614 if (transferAgents[i].isSupportedType(transferData)){
619 if (transferIndex == -1) return COM.DV_E_FORMATETC;
620 transferAgents[transferIndex].javaToNative(data[transferIndex], transferData);
621 COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
622 return transferData.result;
625 private int QueryGetData(long pFormatetc) {
626 if (transferAgents == null) return COM.E_FAIL;
627 TransferData transferData = new TransferData();
628 transferData.formatetc = new FORMATETC();
629 COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
630 transferData.type = transferData.formatetc.cfFormat;
631 if (transferData.type == CFSTR_PREFERREDDROPEFFECT) return COM.S_OK;
632 // is this type supported by the transfer agent?
633 for (int i = 0; i < transferAgents.length; i++){
634 if (transferAgents[i].isSupportedType(transferData))
638 return COM.DV_E_FORMATETC;
640 /* QueryInterface([in] iid, [out] ppvObject)
641 * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
642 * must be incremented before returning. Caller is responsible for releasing ppvObject.
644 private int QueryInterface(long riid, long ppvObject) {
645 if (riid == 0 || ppvObject == 0) return COM.E_INVALIDARG;
646 GUID guid = new GUID();
647 COM.MoveMemory(guid, riid, GUID.sizeof);
648 if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDataObject) ) {
649 OS.MoveMemory(ppvObject, new long[] {iDataObject.getAddress()}, C.PTR_SIZEOF);
653 OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
654 return COM.E_NOINTERFACE;
656 private int Release() {
659 this.data = new Object[0];
660 this.transferAgents = new Transfer[0];
661 disposeCOMInterfaces();
662 if (COM.FreeUnusedLibraries) {
663 COM.CoFreeUnusedLibraries();
670 * Returns an array of the data types currently available on the system
671 * clipboard. Use with Transfer.isSupportedType.
673 * @return array of data types currently available on the system clipboard
675 * @exception SWTException <ul>
676 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
677 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
680 * @see Transfer#isSupportedType
684 public TransferData[] getAvailableTypes() {
685 return getAvailableTypes(DND.CLIPBOARD);
689 * Returns an array of the data types currently available on the specified
690 * clipboard. Use with Transfer.isSupportedType.
692 * <p>The clipboards value is either one of the clipboard constants defined in
693 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
694 * (that is, using the <code>int</code> "|" operator) two or more
695 * of those <code>DND</code> clipboard constants.</p>
697 * @param clipboards from which to get the data types
698 * @return array of data types currently available on the specified clipboard
700 * @exception SWTException <ul>
701 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
702 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
705 * @see Transfer#isSupportedType
707 * @see DND#SELECTION_CLIPBOARD
711 public TransferData[] getAvailableTypes(int clipboards) {
713 if ((clipboards & DND.CLIPBOARD) == 0) return new TransferData[0];
714 FORMATETC[] types = _getAvailableTypes();
715 TransferData[] data = new TransferData[types.length];
716 for (int i = 0; i < types.length; i++) {
717 data[i] = new TransferData();
718 data[i].type = types[i].cfFormat;
719 data[i].formatetc = types[i];
725 * Returns a platform specific list of the data types currently available on the
728 * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer
729 * sub-class. It should NOT be used within an application because it provides
730 * platform specific information.</p>
732 * @return a platform specific list of the data types currently available on the
735 * @exception SWTException <ul>
736 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
737 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
740 public String[] getAvailableTypeNames() {
742 FORMATETC[] types = _getAvailableTypes();
743 String[] names = new String[types.length];
745 for (int i = 0; i < types.length; i++){
746 char [] buffer = new char [maxSize];
747 int size = OS.GetClipboardFormatName(types[i].cfFormat, buffer, maxSize);
749 names[i] = new String (buffer, 0, size);
751 switch (types[i].cfFormat) {
752 case COM.CF_HDROP: names[i] = "CF_HDROP"; break; //$NON-NLS-1$
753 case COM.CF_TEXT: names[i] = "CF_TEXT"; break; //$NON-NLS-1$
754 case COM.CF_BITMAP: names[i] = "CF_BITMAP"; break; //$NON-NLS-1$
755 case COM.CF_METAFILEPICT: names[i] = "CF_METAFILEPICT"; break; //$NON-NLS-1$
756 case COM.CF_SYLK: names[i] = "CF_SYLK"; break; //$NON-NLS-1$
757 case COM.CF_DIF: names[i] = "CF_DIF"; break; //$NON-NLS-1$
758 case COM.CF_TIFF: names[i] = "CF_TIFF"; break; //$NON-NLS-1$
759 case COM.CF_OEMTEXT: names[i] = "CF_OEMTEXT"; break; //$NON-NLS-1$
760 case COM.CF_DIB: names[i] = "CF_DIB"; break; //$NON-NLS-1$
761 case COM.CF_PALETTE: names[i] = "CF_PALETTE"; break; //$NON-NLS-1$
762 case COM.CF_PENDATA: names[i] = "CF_PENDATA"; break; //$NON-NLS-1$
763 case COM.CF_RIFF: names[i] = "CF_RIFF"; break; //$NON-NLS-1$
764 case COM.CF_WAVE: names[i] = "CF_WAVE"; break; //$NON-NLS-1$
765 case COM.CF_UNICODETEXT: names[i] = "CF_UNICODETEXT"; break; //$NON-NLS-1$
766 case COM.CF_ENHMETAFILE: names[i] = "CF_ENHMETAFILE"; break; //$NON-NLS-1$
767 case COM.CF_LOCALE: names[i] = "CF_LOCALE"; break; //$NON-NLS-1$
768 case COM.CF_MAX: names[i] = "CF_MAX"; break; //$NON-NLS-1$
769 default: names[i] = "UNKNOWN"; //$NON-NLS-1$
776 private FORMATETC[] _getAvailableTypes() {
777 FORMATETC[] types = new FORMATETC[0];
778 long[] ppv = new long[1];
779 /* OleGetClipboard([out] ppDataObject).
780 * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
782 if (COM.OleGetClipboard(ppv) != COM.S_OK) return types;
783 IDataObject dataObject = new IDataObject(ppv[0]);
784 long[] ppFormatetc = new long[1];
785 /* EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
786 * AddRef has already been called on ppenumFormatetc by the callee and must be released by the caller.
788 int rc = dataObject.EnumFormatEtc(COM.DATADIR_GET, ppFormatetc);
789 dataObject.Release();
790 if (rc != COM.S_OK)return types;
791 IEnumFORMATETC enumFormatetc = new IEnumFORMATETC(ppFormatetc[0]);
792 // Loop over enumerator and save any types that match what we are looking for
793 long rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
794 int[] pceltFetched = new int[1];
795 enumFormatetc.Reset();
796 while (enumFormatetc.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
797 FORMATETC formatetc = new FORMATETC();
798 COM.MoveMemory(formatetc, rgelt, FORMATETC.sizeof);
799 FORMATETC[] newTypes = new FORMATETC[types.length + 1];
800 System.arraycopy(types, 0, newTypes, 0, types.length);
801 newTypes[types.length] = formatetc;
804 OS.GlobalFree(rgelt);
805 enumFormatetc.Release();