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