]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/Variant.java
Work around SWT 4.13 - 4.18 Win32 DnD bug 567422
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / ole / win32 / Variant.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 IBM Corporation and others.
3  *
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/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.ole.win32;
15
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.internal.*;
18 import org.eclipse.swt.internal.ole.win32.*;
19 import org.eclipse.swt.internal.win32.*;
20 /**
21  *
22  * A Variant is a generic OLE mechanism for passing data of different types via a common interface.
23  *
24  * <p>It is used within the OleAutomation object for getting a property, setting a property or invoking
25  * a method on an OLE Control or OLE Document.
26  *
27  */
28 public final class Variant {
29         /**
30         * The size in bytes of a native VARIANT struct.
31         */
32         public static final int sizeof = VARIANT.sizeof;
33
34         private short type; // OLE.VT_* type
35         private boolean booleanData;
36         private byte    byteData;
37         private short   shortData;
38         private char    charData;
39         private int     intData;
40         private long    longData;
41         private float   floatData;
42         private double  doubleData;
43         private String  stringData;
44         private long     byRefPtr;
45         private IDispatch dispatchData;
46         private IUnknown unknownData;
47
48         /**
49          * A shared Variant instance with type VT_NULL.
50          *
51          * @since 3.7
52          */
53         public static final Variant NULL;
54         static {
55                 NULL = new Variant ();
56                 NULL.type = COM.VT_NULL;
57         }
58
59 /**
60  * Invokes platform specific functionality to copy a variant
61  * into operating system memory.
62  * <p>
63  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
64  * API for <code>Variant</code>. It is marked public only so that it
65  * can be shared within the packages provided by SWT. It is not
66  * available on all platforms, and should never be called from
67  * application code.
68  * </p>
69  *
70  * @param pVarDest destination pointer to a variant
71  * @param varSrc source <code>Variant</code>
72  *
73  * @noreference This method is not intended to be referenced by clients.
74  *
75  * @since 3.3
76  */
77 public static void win32_copy (long pVarDest, Variant varSrc) {
78         varSrc.getData (pVarDest);
79 }
80
81 /**
82  * Invokes platform specific functionality to wrap a variant
83  * that was allocated in operating system memory.
84  * <p>
85  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
86  * API for <code>Variant</code>. It is marked public only so that it
87  * can be shared within the packages provided by SWT. It is not
88  * available on all platforms, and should never be called from
89  * application code.
90  * </p>
91  *
92  * @param pVariant pointer to a variant
93  *
94  * @return a new <code>Variant</code>
95  *
96  * @noreference This method is not intended to be referenced by clients.
97  *
98  * @since 3.3
99  */
100 public static Variant win32_new (long pVariant) {
101         Variant variant = new Variant ();
102         variant.setData (pVariant);
103         return variant;
104 }
105
106 /**
107  * Create an empty Variant object with type VT_EMPTY.
108  *
109  * @since 2.0
110  */
111 public Variant() {
112         type = COM.VT_EMPTY;
113 }
114 /**
115  * Create a Variant object which represents a Java float as a VT_R4.
116  *
117  * @param val the Java float value that this Variant represents
118  *
119  */
120 public Variant(float val) {
121         type = COM.VT_R4;
122         floatData = val;
123 }
124 /**
125  * Create a Variant object which represents a Java double as a VT_R8.
126  *
127  * @param val the Java double value that this Variant represents
128  *
129  * @since 3.2
130  */
131 public Variant(double val) {
132         type = COM.VT_R8;
133         doubleData = val;
134 }
135 /**
136  * Create a Variant object which represents a Java int as a VT_I4.
137  *
138  * @param val the Java int value that this Variant represents
139  *
140  */
141  public Variant(int val) {
142         type = COM.VT_I4;
143         intData = val;
144 }
145 /**
146  * Create a Variant object which contains a reference to the data being transferred.
147  *
148  * <p>When creating a VT_BYREF Variant, you must give the full Variant type
149  * including VT_BYREF such as
150  *
151  * <pre><code>short byRefType = OLE.VT_BSTR | OLE.VT_BYREF</code></pre>.
152  *
153  * @param ptr a pointer to the data being transferred.
154  * @param byRefType the type of the data being transferred such as OLE.VT_BSTR | OLE.VT_BYREF
155  *
156  */
157 public Variant(long ptr, short byRefType) {
158         type = byRefType;
159         byRefPtr = ptr;
160 }
161 /**
162  * Create a Variant object which represents an IDispatch interface as a VT_Dispatch.
163  *
164  * @param automation the OleAutomation object that this Variant represents
165  *
166  */
167 public Variant(OleAutomation automation) {
168         type = COM.VT_DISPATCH;
169         dispatchData = new IDispatch(automation.getAddress());
170 }
171 /**
172  * Create a Variant object which represents an IDispatch interface as a VT_Dispatch.
173  * <p>The caller is expected to have appropriately invoked unknown.AddRef() before creating
174  * this Variant.
175  *
176  * @since 2.0
177  *
178  * @param idispatch the IDispatch object that this Variant represents
179  *
180  */
181 public Variant(IDispatch idispatch) {
182         type = COM.VT_DISPATCH;
183         dispatchData = idispatch;
184 }
185 /**
186  * Create a Variant object which represents an IUnknown interface as a VT_UNKNOWN.
187  *
188  * <p>The caller is expected to have appropriately invoked unknown.AddRef() before creating
189  * this Variant.
190  *
191  * @param unknown the IUnknown object that this Variant represents
192  *
193  */
194 public Variant(IUnknown unknown) {
195         type = COM.VT_UNKNOWN;
196         unknownData = unknown;
197 }
198 /**
199  * Create a Variant object which represents a Java long as a VT_I8.
200  *
201  * @param val the Java long value that this Variant represents
202  *
203  * @since 3.2
204  */
205  public Variant(long val) {
206         type = COM.VT_I8;
207         longData = val;
208 }
209 /**
210  * Create a Variant object which represents a Java String as a VT_BSTR.
211  *
212  * @param string the Java String value that this Variant represents
213  *
214  */
215 public Variant(String string) {
216         type = COM.VT_BSTR;
217         stringData = string;
218 }
219 /**
220  * Create a Variant object which represents a Java short as a VT_I2.
221  *
222  * @param val the Java short value that this Variant represents
223  *
224  */
225 public Variant(short val) {
226         type = COM.VT_I2;
227         shortData = val;
228 }
229 /**
230  * Create a Variant object which represents a Java boolean as a VT_BOOL.
231  *
232  * @param val the Java boolean value that this Variant represents
233  *
234  */
235 public Variant(boolean val) {
236         type = COM.VT_BOOL;
237         booleanData = val;
238 }
239
240 /**
241  * Calling dispose will release resources associated with this Variant.
242  * If the resource is an IDispatch or IUnknown interface, Release will be called.
243  * If the resource is a ByRef pointer, nothing is released.
244  *
245  * @since 2.1
246  */
247 public void dispose() {
248         if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
249                 return;
250         }
251
252         switch (type) {
253                 case COM.VT_DISPATCH :
254                         dispatchData.Release();
255                         break;
256                 case COM.VT_UNKNOWN :
257                         unknownData.Release();
258                         break;
259         }
260
261 }
262 /**
263  * Returns the OleAutomation object represented by this Variant.
264  *
265  * <p>If this Variant does not contain an OleAutomation object, an attempt is made to
266  * coerce the Variant type into an OleAutomation object.  If this fails, an error is
267  * thrown.  Note that OleAutomation objects must be disposed when no longer
268  * needed.
269  *
270  * @return the OleAutomation object represented by this Variant
271  *
272  * @exception SWTException <ul>
273  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into an OleAutomation object</li>
274  * </ul>
275  */
276 public OleAutomation getAutomation() {
277         if (type == COM.VT_EMPTY) {
278                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
279         }
280         if (type == COM.VT_DISPATCH) {
281                 return new OleAutomation(dispatchData);
282         }
283         // try to coerce the value to the desired type
284         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
285         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
286         try {
287                 getData(oldPtr);
288                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_DISPATCH);
289                 if (result != COM.S_OK)
290                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
291                 Variant autoVar = new Variant();
292                 autoVar.setData(newPtr);
293                 return autoVar.getAutomation();
294         } finally {
295                 COM.VariantClear(oldPtr);
296                 OS.GlobalFree(oldPtr);
297                 COM.VariantClear(newPtr); // Note: This must absolutely be done AFTER the
298                                           // OleAutomation object is created as Variant Clear
299                                           // will result in a Release being performed on the
300                                           // Dispatch object
301                 OS.GlobalFree(newPtr);
302         }
303 }
304 /**
305  * Returns the IDispatch object represented by this Variant.
306  *
307  * <p>If this Variant does not contain an IDispatch object, an attempt is made to
308  * coerce the Variant type into an IDIspatch object.  If this fails, an error is
309  * thrown.
310  *
311  * @since 2.0
312  *
313  * @return the IDispatch object represented by this Variant
314  *
315  * @exception SWTException <ul>
316  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into an IDispatch object</li>
317  * </ul>
318  */
319 public IDispatch getDispatch() {
320         if (type == COM.VT_EMPTY) {
321                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
322         }
323         if (type == COM.VT_DISPATCH) {
324                 return dispatchData;
325         }
326         // try to coerce the value to the desired type
327         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
328         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
329         try {
330                 getData(oldPtr);
331                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_DISPATCH);
332                 if (result != COM.S_OK)
333                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
334                 Variant autoVar = new Variant();
335                 autoVar.setData(newPtr);
336                 return autoVar.getDispatch();
337         } finally {
338                 COM.VariantClear(oldPtr);
339                 OS.GlobalFree(oldPtr);
340                 COM.VariantClear(newPtr); // Note: This must absolutely be done AFTER the
341                                           // OleAutomation object is created as Variant Clear
342                                           // will result in a Release being performed on the
343                                           // Dispatch object
344                 OS.GlobalFree(newPtr);
345         }
346 }
347 /**
348  * Returns the Java boolean represented by this Variant.
349  *
350  * <p>If this Variant does not contain a Java boolean, an attempt is made to
351  * coerce the Variant type into a Java boolean.  If this fails, an error is thrown.
352  *
353  * @return the Java boolean represented by this Variant
354  *
355  * @exception SWTException <ul>
356  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a boolean</li>
357  * </ul>
358  *
359  */
360 public boolean getBoolean() {
361         if (type == COM.VT_EMPTY) {
362                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
363         }
364         if (type == COM.VT_BOOL) {
365                 return booleanData;
366         }
367
368         // try to coerce the value to the desired type
369         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
370         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
371         try {
372                 getData(oldPtr);
373                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_BOOL);
374                 if (result != COM.S_OK)
375                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
376                 Variant boolVar = new Variant();
377                 boolVar.setData(newPtr);
378                 return boolVar.getBoolean();
379         } finally {
380                 COM.VariantClear(oldPtr);
381                 OS.GlobalFree(oldPtr);
382                 COM.VariantClear(newPtr);
383                 OS.GlobalFree(newPtr);
384         }
385 }
386 /**
387  * Returns a pointer to the referenced data represented by this Variant.
388  *
389  * <p>If this Variant does not contain a reference to data, zero is returned.
390  *
391  * @return a pointer to the referenced data represented by this Variant or 0
392  *
393  */
394 public long getByRef() {
395         if (type == COM.VT_EMPTY) {
396                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
397         }
398         if ((type & COM.VT_BYREF)== COM.VT_BYREF) {
399                 return byRefPtr;
400         }
401
402         return 0;
403 }
404 /**
405  * Returns the Java byte represented by this Variant.
406  *
407  * <p>If this Variant does not contain a Java byte, an attempt is made to
408  * coerce the Variant type into a Java byte.  If this fails, an error is thrown.
409  *
410  * @return the Java byte represented by this Variant
411  *
412  * @exception SWTException <ul>
413  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a byte</li>
414  * </ul>
415  *
416  * @since 3.3
417  */
418 public byte getByte() {
419         if (type == COM.VT_EMPTY) {
420                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
421         }
422         if (type == COM.VT_I1) {
423                 return byteData;
424         }
425
426         // try to coerce the value to the desired type
427         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
428         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
429         try {
430                 getData(oldPtr);
431                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_I1);
432                 if (result != COM.S_OK)
433                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
434                 Variant byteVar = new Variant();
435                 byteVar.setData(newPtr);
436                 return byteVar.getByte();
437         } finally {
438                 COM.VariantClear(oldPtr);
439                 OS.GlobalFree(oldPtr);
440                 COM.VariantClear(newPtr);
441                 OS.GlobalFree(newPtr);
442         }
443 }
444 /**
445  * Returns the Java char represented by this Variant.
446  *
447  * <p>If this Variant does not contain a Java char, an attempt is made to
448  * coerce the Variant type into a Java char.  If this fails, an error is thrown.
449  *
450  * @return the Java char represented by this Variant
451  *
452  * @exception SWTException <ul>
453  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a char</li>
454  * </ul>
455  *
456  * @since 3.3
457  */
458 public char getChar() {
459         if (type == COM.VT_EMPTY) {
460                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
461         }
462         if (type == COM.VT_UI2) {
463                 return charData;
464         }
465
466         // try to coerce the value to the desired type
467         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
468         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
469         try {
470                 getData(oldPtr);
471                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_UI2);
472                 if (result != COM.S_OK)
473                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
474                 Variant charVar = new Variant();
475                 charVar.setData(newPtr);
476                 return charVar.getChar();
477         } finally {
478                 COM.VariantClear(oldPtr);
479                 OS.GlobalFree(oldPtr);
480                 COM.VariantClear(newPtr);
481                 OS.GlobalFree(newPtr);
482         }
483 }
484 void getData(long pData){
485         if (pData == 0) OLE.error(OLE.ERROR_OUT_OF_MEMORY);
486
487         COM.VariantInit(pData);
488
489         if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
490                 //TODO - use VARIANT structure
491                 OS.MoveMemory(pData, new short[] {type}, 2);
492                 OS.MoveMemory(pData + 8, new long[]{byRefPtr}, C.PTR_SIZEOF);
493                 return;
494         }
495
496         switch (type) {
497                 case COM.VT_EMPTY :
498                 case COM.VT_NULL :
499                         OS.MoveMemory(pData, new short[] {type}, 2);
500                         break;
501                 case COM.VT_BOOL :
502                         OS.MoveMemory(pData, new short[] {type}, 2);
503                         OS.MoveMemory(pData + 8, new short[]{(booleanData) ? OS.VARIANT_TRUE : OS.VARIANT_FALSE}, 2);
504                         break;
505                 case COM.VT_I1 :
506                         OS.MoveMemory(pData, new short[] {type}, 2);
507                         OS.MoveMemory(pData + 8, new byte[]{byteData}, 1);
508                         break;
509                 case COM.VT_I2 :
510                         OS.MoveMemory(pData, new short[] {type}, 2);
511                         OS.MoveMemory(pData + 8, new short[]{shortData}, 2);
512                         break;
513                 case COM.VT_UI2 :
514                         OS.MoveMemory(pData, new short[] {type}, 2);
515                         OS.MoveMemory(pData + 8, new char[]{charData}, 2);
516                         break;
517                 case COM.VT_I4 :
518                         OS.MoveMemory(pData, new short[] {type}, 2);
519                         OS.MoveMemory(pData + 8, new int[]{intData}, 4);
520                         break;
521                 case COM.VT_I8 :
522                         OS.MoveMemory(pData, new short[] {type}, 2);
523                         OS.MoveMemory(pData + 8, new long[]{longData}, 8);
524                         break;
525                 case COM.VT_R4 :
526                         OS.MoveMemory(pData, new short[] {type}, 2);
527                         OS.MoveMemory(pData + 8, new float[]{floatData}, 4);
528                         break;
529                 case COM.VT_R8 :
530                         OS.MoveMemory(pData, new short[] {type}, 2);
531                         OS.MoveMemory(pData + 8, new double[]{doubleData}, 8);
532                         break;
533                 case COM.VT_DISPATCH :
534                         dispatchData.AddRef();
535                         OS.MoveMemory(pData, new short[] {type}, 2);
536                         OS.MoveMemory(pData + 8, new long[]{dispatchData.getAddress()}, C.PTR_SIZEOF);
537                         break;
538                 case COM.VT_UNKNOWN :
539                         unknownData.AddRef();
540                         OS.MoveMemory(pData, new short[] {type}, 2);
541                         OS.MoveMemory(pData + 8, new long[]{unknownData.getAddress()}, C.PTR_SIZEOF);
542                         break;
543                 case COM.VT_BSTR :
544                         OS.MoveMemory(pData, new short[] {type}, 2);
545                         char[] data = (stringData+"\0").toCharArray();
546                         long ptr = COM.SysAllocString(data);
547                         OS.MoveMemory(pData + 8, new long[] {ptr}, C.PTR_SIZEOF);
548                         break;
549
550                 default :
551                         OLE.error(SWT.ERROR_NOT_IMPLEMENTED);
552         }
553 }
554 /**
555  * Returns the Java double represented by this Variant.
556  *
557  * <p>If this Variant does not contain a Java double, an attempt is made to
558  * coerce the Variant type into a Java double.  If this fails, an error is thrown.
559  *
560  * @return the Java double represented by this Variant
561  *
562  * @exception SWTException <ul>
563  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a double</li>
564  * </ul>
565  *
566  * @since 3.2
567  */
568 public double getDouble() {
569         if (type == COM.VT_EMPTY) {
570                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
571         }
572         if (type == COM.VT_R8) {
573                 return doubleData;
574         }
575
576         // try to coerce the value to the desired type
577         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
578         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
579         try {
580                 getData(oldPtr);
581                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_R8);
582                 if (result != COM.S_OK)
583                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
584                 Variant doubleVar = new Variant();
585                 doubleVar.setData(newPtr);
586                 return doubleVar.getDouble();
587         } finally {
588                 COM.VariantClear(oldPtr);
589                 OS.GlobalFree(oldPtr);
590                 COM.VariantClear(newPtr);
591                 OS.GlobalFree(newPtr);
592         }
593 }
594
595 /**
596  * Returns the Java float represented by this Variant.
597  *
598  * <p>If this Variant does not contain a Java float, an attempt is made to
599  * coerce the Variant type into a Java float.  If this fails, an error is thrown.
600  *
601  * @return the Java float represented by this Variant
602  *
603  * @exception SWTException <ul>
604  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a float</li>
605  * </ul>
606  */
607 public float getFloat() {
608         if (type == COM.VT_EMPTY) {
609                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
610         }
611         if (type == COM.VT_R4) {
612                 return floatData;
613         }
614
615         // try to coerce the value to the desired type
616         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
617         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
618         try {
619                 getData(oldPtr);
620                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_R4);
621                 if (result != COM.S_OK)
622                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
623                 Variant floatVar = new Variant();
624                 floatVar.setData(newPtr);
625                 return floatVar.getFloat();
626         } finally {
627                 COM.VariantClear(oldPtr);
628                 OS.GlobalFree(oldPtr);
629                 COM.VariantClear(newPtr);
630                 OS.GlobalFree(newPtr);
631         }
632
633 }
634 /**
635  * Returns the Java int represented by this Variant.
636  *
637  * <p>If this Variant does not contain a Java int, an attempt is made to
638  * coerce the Variant type into a Java int.  If this fails, an error is thrown.
639  *
640  * @return the Java int represented by this Variant
641  *
642  * @exception SWTException <ul>
643  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a int</li>
644  * </ul>
645  */
646 public int getInt() {
647         if (type == COM.VT_EMPTY) {
648                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
649         }
650         if (type == COM.VT_I4) {
651                 return intData;
652         }
653
654         // try to coerce the value to the desired type
655         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
656         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
657         try {
658                 getData(oldPtr);
659                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_I4);
660                 if (result != COM.S_OK)
661                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
662                 Variant intVar = new Variant();
663                 intVar.setData(newPtr);
664                 return intVar.getInt();
665         } finally {
666                 COM.VariantClear(oldPtr);
667                 OS.GlobalFree(oldPtr);
668                 COM.VariantClear(newPtr);
669                 OS.GlobalFree(newPtr);
670         }
671 }
672 /**
673  * Returns the Java long represented by this Variant.
674  *
675  * <p>If this Variant does not contain a Java long, an attempt is made to
676  * coerce the Variant type into a Java long.  If this fails, an error is thrown.
677  *
678  * @return the Java long represented by this Variant
679  *
680  * @exception SWTException <ul>
681  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a long</li>
682  * </ul>
683  *
684  * @since 3.2
685  */
686 public long getLong() {
687         if (type == COM.VT_EMPTY) {
688                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
689         }
690         if (type == COM.VT_I8) {
691                 return longData;
692         }
693
694         // try to coerce the value to the desired type
695         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
696         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
697         try {
698                 getData(oldPtr);
699                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_I8);
700                 if (result != COM.S_OK)
701                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
702                 Variant longVar = new Variant();
703                 longVar.setData(newPtr);
704                 return longVar.getLong();
705         } finally {
706                 COM.VariantClear(oldPtr);
707                 OS.GlobalFree(oldPtr);
708                 COM.VariantClear(newPtr);
709                 OS.GlobalFree(newPtr);
710         }
711 }
712 /**
713  * Returns the Java short represented by this Variant.
714  *
715  * <p>If this Variant does not contain a Java short, an attempt is made to
716  * coerce the Variant type into a Java short.  If this fails, an error is thrown.
717  *
718  * @return the Java short represented by this Variant
719  *
720  * @exception SWTException <ul>
721  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a short</li>
722  * </ul>
723  */
724 public short getShort() {
725         if (type == COM.VT_EMPTY) {
726                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
727         }
728         if (type == COM.VT_I2) {
729                 return shortData;
730         }
731
732         // try to coerce the value to the desired type
733         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
734         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
735         try {
736                 getData(oldPtr);
737                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_I2);
738                 if (result != COM.S_OK)
739                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
740                 Variant shortVar = new Variant();
741                 shortVar.setData(newPtr);
742                 return shortVar.getShort();
743         } finally {
744                 COM.VariantClear(oldPtr);
745                 OS.GlobalFree(oldPtr);
746                 COM.VariantClear(newPtr);
747                 OS.GlobalFree(newPtr);
748         }
749
750 }
751 /**
752  * Returns the Java String represented by this Variant.
753  *
754  * <p>If this Variant does not contain a Java String, an attempt is made to
755  * coerce the Variant type into a Java String.  If this fails, an error is thrown.
756  *
757  * @return the Java String represented by this Variant
758  *
759  * @exception SWTException <ul>
760  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a String</li>
761  * </ul>
762  */
763 public String getString() {
764         if (type == COM.VT_EMPTY) {
765                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
766         }
767         if (type == COM.VT_BSTR) {
768                 return stringData;
769         }
770
771         // try to coerce the value to the desired type
772         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
773         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
774         try {
775                 getData(oldPtr);
776                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_BSTR);
777                 if (result != COM.S_OK)
778                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
779
780                 Variant stringVar = new Variant();
781                 stringVar.setData(newPtr);
782                 return stringVar.getString();
783
784         } finally {
785                 COM.VariantClear(oldPtr);
786                 OS.GlobalFree(oldPtr);
787                 COM.VariantClear(newPtr);
788                 OS.GlobalFree(newPtr);
789         }
790 }
791 /**
792  * Returns the type of the variant type.  This will be an OLE.VT_* value or
793  * a bitwise combination of OLE.VT_* values as in the case of
794  * OLE.VT_BSTR | OLE.VT_BYREF.
795  *
796  * @return the type of the variant data
797  *
798  * @since 2.0
799  */
800 public short getType() {
801         return type;
802 }
803 /**
804  * Returns the IUnknown object represented by this Variant.
805  *
806  * <p>If this Variant does not contain an IUnknown object, an attempt is made to
807  * coerce the Variant type into an IUnknown object.  If this fails, an error is
808  * thrown.
809  *
810  * @return the IUnknown object represented by this Variant
811  *
812  * @exception SWTException <ul>
813  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into
814  *                      an IUnknown object</li>
815  * </ul>
816  */
817 public IUnknown getUnknown() {
818         if (type == COM.VT_EMPTY) {
819                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
820         }
821         if (type == COM.VT_UNKNOWN) {
822                 return unknownData;
823         }
824
825         // try to coerce the value to the desired type
826         long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
827         long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
828         try {
829                 getData(oldPtr);
830                 int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_UNKNOWN);
831                 if (result != COM.S_OK)
832                         OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
833                 Variant unknownVar = new Variant();
834                 unknownVar.setData(newPtr);
835                 return unknownVar.getUnknown();
836         } finally {
837                 COM.VariantClear(oldPtr);
838                 OS.GlobalFree(oldPtr);
839                 COM.VariantClear(newPtr); // Note: This must absolutely be done AFTER the
840                                           // IUnknown object is created as Variant Clear
841                                           // will result in a Release being performed on the
842                                           // Dispatch object
843                 OS.GlobalFree(newPtr);
844         }
845 }
846 /**
847  * Update the by reference value of this variant with a new boolean value.
848  *
849  * @param val the new boolean value
850  *
851  * @exception SWTException <ul>
852  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not
853  *                      a (VT_BYREF | VT_BOOL) object</li>
854  * </ul>
855  *
856  * @since 2.1
857  */
858 public void setByRef(boolean val) {
859         if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_BOOL) == 0) {
860                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
861         }
862         OS.MoveMemory(byRefPtr, new short[]{val ? OS.VARIANT_TRUE : OS.VARIANT_FALSE}, 2);
863 }
864 /**
865  * Update the by reference value of this variant with a new float value.
866  *
867  * @param val the new float value
868  *
869  * @exception SWTException <ul>
870  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not
871  *                      a (VT_BYREF | VT_R4) object</li>
872  * </ul>
873  *
874  * @since 2.1
875  */
876 public void setByRef(float val) {
877         if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_R4) == 0) {
878                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
879         }
880         OS.MoveMemory(byRefPtr, new float[]{val}, 4);
881 }
882 /**
883  * Update the by reference value of this variant with a new integer value.
884  *
885  * @param val the new integer value
886  *
887  * @exception SWTException <ul>
888  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not a (VT_BYREF | VT_I4) object</li>
889  * </ul>
890  *
891  * @since 2.1
892  */
893 public void setByRef(long val) {
894         if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_I8) == 0) {
895                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
896         }
897         OS.MoveMemory(byRefPtr, new long[]{val}, C.PTR_SIZEOF);
898 }
899 /**
900  * Update the by reference value of this variant with a new short value.
901  *
902  * @param val the new short value
903  *
904  * @exception SWTException <ul>
905  *     <li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not a (VT_BYREF | VT_I2) object
906  * </ul>
907  *
908  * @since 2.1
909  */
910 public void setByRef(short val) {
911         if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_I2) == 0) {
912                 OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
913         }
914         OS.MoveMemory(byRefPtr, new short[]{val}, 2);
915 }
916 void setData(long pData){
917         if (pData == 0) OLE.error(SWT.ERROR_INVALID_ARGUMENT);
918
919         //TODO - use VARIANT structure
920         short[] dataType = new short[1];
921         OS.MoveMemory(dataType, pData, 2);
922         type = dataType[0];
923
924         if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
925                 long[] newByRefPtr = new long[1];
926                 OS.MoveMemory(newByRefPtr, pData + 8, C.PTR_SIZEOF);
927                 byRefPtr = newByRefPtr[0];
928                 return;
929         }
930
931         switch (type) {
932                 case COM.VT_EMPTY :
933                 case COM.VT_NULL :
934                         break;
935                 case COM.VT_BOOL :
936                         short[] newBooleanData = new short[1];
937                         OS.MoveMemory(newBooleanData, pData + 8, 2);
938                         booleanData = (newBooleanData[0] != OS.VARIANT_FALSE);
939                         break;
940                 case COM.VT_I1 :
941                         byte[] newByteData = new byte[1];
942                         OS.MoveMemory(newByteData, pData + 8, 1);
943                         byteData = newByteData[0];
944                         break;
945                 case COM.VT_I2 :
946                         short[] newShortData = new short[1];
947                         OS.MoveMemory(newShortData, pData + 8, 2);
948                         shortData = newShortData[0];
949                         break;
950                 case COM.VT_UI2 :
951                         char[] newCharData = new char[1];
952                         OS.MoveMemory(newCharData, pData + 8, 2);
953                         charData = newCharData[0];
954                         break;
955                 case COM.VT_I4 :
956                         int[] newIntData = new int[1];
957                         OS.MoveMemory(newIntData, pData + 8, 4);
958                         intData = newIntData[0];
959                         break;
960                 case COM.VT_I8 :
961                         long[] newLongData = new long[1];
962                         OS.MoveMemory(newLongData, pData + 8, 8);
963                         longData = newLongData[0];
964                         break;
965                 case COM.VT_R4 :
966                         float[] newFloatData = new float[1];
967                         OS.MoveMemory(newFloatData, pData + 8, 4);
968                         floatData = newFloatData[0];
969                         break;
970                 case COM.VT_R8 :
971                         double[] newDoubleData = new double[1];
972                         OS.MoveMemory(newDoubleData, pData + 8, 8);
973                         doubleData = newDoubleData[0];
974                         break;
975                 case COM.VT_DISPATCH : {
976                         long[] ppvObject = new long[1];
977                         OS.MoveMemory(ppvObject, pData + 8, C.PTR_SIZEOF);
978                         if (ppvObject[0] == 0) {
979                                 type = COM.VT_EMPTY;
980                                 break;
981                         }
982                         dispatchData = new IDispatch(ppvObject[0]);
983                         dispatchData.AddRef();
984                         break;
985                 }
986                 case COM.VT_UNKNOWN : {
987                         long[] ppvObject = new long[1];
988                         OS.MoveMemory(ppvObject, pData + 8, C.PTR_SIZEOF);
989                         if (ppvObject[0] == 0) {
990                                 type = COM.VT_EMPTY;
991                                 break;
992                         }
993                         unknownData = new IUnknown(ppvObject[0]);
994                         unknownData.AddRef();
995                         break;
996                 }
997                 case COM.VT_BSTR :
998                         // get the address of the memory in which the string resides
999                         long[] hMem = new long[1];
1000                         OS.MoveMemory(hMem, pData + 8, C.PTR_SIZEOF);
1001                         if (hMem[0] == 0) {
1002                                 type = COM.VT_EMPTY;
1003                                 break;
1004                         }
1005                         // Get the size of the string from the OS - the size is expressed in number
1006                         // of bytes - each unicode character is 2 bytes.
1007                         int size = COM.SysStringByteLen(hMem[0]);
1008                         if (size > 0){
1009                                 // get the unicode character array from the global memory and create a String
1010                                 char[] buffer = new char[(size + 1) /2]; // add one to avoid rounding errors
1011                                 OS.MoveMemory(buffer, hMem[0], size);
1012                                 stringData = new String(buffer);
1013                         } else {
1014                                 stringData = ""; //$NON-NLS-1$
1015                         }
1016                         break;
1017
1018                 default :
1019                         // try coercing it into one of the known forms
1020                         long newPData = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, sizeof);
1021                         if (COM.VariantChangeType(newPData, pData, (short) 0, COM.VT_R8) == COM.S_OK) {
1022                                 setData(newPData);
1023                         } else if (COM.VariantChangeType(newPData, pData, (short) 0, COM.VT_I8) == COM.S_OK) {
1024                                 setData(newPData);
1025                         } else if (COM.VariantChangeType(newPData, pData, (short) 0, COM.VT_BSTR) == COM.S_OK) {
1026                                 setData(newPData);
1027                         }
1028                         COM.VariantClear(newPData);
1029                         OS.GlobalFree(newPData);
1030                         break;
1031         }
1032 }
1033 /**
1034  * Returns a string containing a concise, human-readable
1035  * description of the receiver.
1036  *
1037  * @return a string representation of the Variant
1038  */
1039 @Override
1040 public String toString () {
1041         switch (type) {
1042                 case COM.VT_BOOL :
1043                         return "VT_BOOL{"+booleanData+"}";
1044                 case COM.VT_I1 :
1045                         return "VT_I1{"+byteData+"}";
1046                 case COM.VT_I2 :
1047                         return "VT_I2{"+shortData+"}";
1048                 case COM.VT_UI2 :
1049                         return "VT_UI2{"+charData+"}";
1050                 case COM.VT_I4 :
1051                         return "VT_I4{"+intData+"}";
1052                 case COM.VT_I8 :
1053                         return "VT_I8{"+longData+"}";
1054                 case COM.VT_R4 :
1055                         return "VT_R4{"+floatData+"}";
1056                 case COM.VT_R8 :
1057                         return "VT_R8{"+doubleData+"}";
1058                 case COM.VT_BSTR :
1059                         return "VT_BSTR{"+stringData+"}";
1060                 case COM.VT_DISPATCH :
1061                         return "VT_DISPATCH{"+(dispatchData == null ? 0 : dispatchData.getAddress())+"}";
1062                 case COM.VT_UNKNOWN :
1063                         return "VT_UNKNOWN{"+(unknownData == null ? 0 : unknownData.getAddress())+"}";
1064                 case COM.VT_EMPTY :
1065                         return "VT_EMPTY";
1066                 case COM.VT_NULL :
1067                         return "VT_NULL";
1068         }
1069         if ((type & COM.VT_BYREF) != 0) {
1070                 return "VT_BYREF|"+(type & ~COM.VT_BYREF)+"{"+byRefPtr+"}";
1071         }
1072         return "Unsupported Type "+type;
1073 }
1074 }