2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Variant.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Microsoft Public License, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Microsoft Public License.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15 using System; using Microsoft;
16
17
18 #if !SILVERLIGHT // ComObject
19
20 using System.Diagnostics;
21 using System.Diagnostics.CodeAnalysis;
22 using System.Globalization;
23 using System.Runtime.InteropServices;
24 using System.Security;
25 using System.Security.Permissions;
26
27 #if CODEPLEX_40
28 namespace System.Dynamic {
29 #else
30 namespace Microsoft.Scripting {
31 #endif
32
33     /// <summary>
34     /// Variant is the basic COM type for late-binding. It can contain any other COM data type.
35     /// This type definition precisely matches the unmanaged data layout so that the struct can be passed
36     /// to and from COM calls.
37     /// </summary>
38     [StructLayout(LayoutKind.Explicit)]
39     internal struct Variant {
40
41 #if DEBUG
42         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2207:InitializeValueTypeStaticFieldsInline")]
43         static Variant() {
44             // Variant size is the size of 4 pointers (16 bytes) on a 32-bit processor, 
45             // and 3 pointers (24 bytes) on a 64-bit processor.
46             int intPtrSize = Marshal.SizeOf(typeof(IntPtr));
47             int variantSize = Marshal.SizeOf(typeof(Variant));
48             if (intPtrSize == 4) {
49                 Debug.Assert(variantSize == (4 * intPtrSize));
50             } else {
51                 Debug.Assert(intPtrSize == 8);
52                 Debug.Assert(variantSize == (3 * intPtrSize));
53             }
54         }
55 #endif
56
57         // Most of the data types in the Variant are carried in _typeUnion
58         [FieldOffset(0)]
59         private TypeUnion _typeUnion;
60
61         // Decimal is the largest data type and it needs to use the space that is normally unused in TypeUnion._wReserved1, etc.
62         // Hence, it is declared to completely overlap with TypeUnion. A Decimal does not use the first two bytes, and so
63         // TypeUnion._vt can still be used to encode the type.
64         [FieldOffset(0)]
65         private Decimal _decimal;
66
67         [StructLayout(LayoutKind.Sequential)]
68         private struct TypeUnion {
69             internal ushort _vt;
70             internal ushort _wReserved1;
71             internal ushort _wReserved2;
72             internal ushort _wReserved3;
73
74             internal UnionTypes _unionTypes;
75         }
76
77         [StructLayout(LayoutKind.Sequential)]
78         private struct Record {
79             private IntPtr _record;
80             private IntPtr _recordInfo;
81         }
82
83         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")]
84         [StructLayout(LayoutKind.Explicit)]
85         private struct UnionTypes {
86             #region Generated Variant union types
87
88             // *** BEGIN GENERATED CODE ***
89             // generated by function: gen_UnionTypes from: generate_comdispatch.py
90
91             [FieldOffset(0)] internal SByte _i1;
92             [FieldOffset(0)] internal Int16 _i2;
93             [FieldOffset(0)] internal Int32 _i4;
94             [FieldOffset(0)] internal Int64 _i8;
95             [FieldOffset(0)] internal Byte _ui1;
96             [FieldOffset(0)] internal UInt16 _ui2;
97             [FieldOffset(0)] internal UInt32 _ui4;
98             [FieldOffset(0)] internal UInt64 _ui8;
99             [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
100             [FieldOffset(0)] internal IntPtr _int;
101             [FieldOffset(0)] internal UIntPtr _uint;
102             [FieldOffset(0)] internal Int16 _bool;
103             [FieldOffset(0)] internal Int32 _error;
104             [FieldOffset(0)] internal Single _r4;
105             [FieldOffset(0)] internal Double _r8;
106             [FieldOffset(0)] internal Int64 _cy;
107             [FieldOffset(0)] internal Double _date;
108             [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
109             [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
110             [FieldOffset(0)] internal IntPtr _bstr;
111             [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
112             [FieldOffset(0)] internal IntPtr _unknown;
113             [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
114             [FieldOffset(0)] internal IntPtr _dispatch;
115
116             // *** END GENERATED CODE ***
117
118             #endregion
119
120             [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
121             [FieldOffset(0)]
122             internal IntPtr _byref;
123             [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
124             [FieldOffset(0)]
125             internal Record _record;
126         }
127
128         public override string ToString() {
129             return String.Format(CultureInfo.CurrentCulture, "Variant ({0})", VariantType);
130         }
131
132         /// <summary>
133         /// Primitive types are the basic COM types. It includes valuetypes like ints, but also reference types
134         /// like BStrs. It does not include composite types like arrays and user-defined COM types (IUnknown/IDispatch).
135         /// </summary>
136         internal static bool IsPrimitiveType(VarEnum varEnum) {
137             switch (varEnum) {
138                 #region Generated Variant IsPrimitiveType
139
140                 // *** BEGIN GENERATED CODE ***
141                 // generated by function: gen_IsPrimitiveType from: generate_comdispatch.py
142
143                 case VarEnum.VT_I1:
144                 case VarEnum.VT_I2:
145                 case VarEnum.VT_I4:
146                 case VarEnum.VT_I8:
147                 case VarEnum.VT_UI1:
148                 case VarEnum.VT_UI2:
149                 case VarEnum.VT_UI4:
150                 case VarEnum.VT_UI8:
151                 case VarEnum.VT_INT:
152                 case VarEnum.VT_UINT:
153                 case VarEnum.VT_BOOL:
154                 case VarEnum.VT_ERROR:
155                 case VarEnum.VT_R4:
156                 case VarEnum.VT_R8:
157                 case VarEnum.VT_DECIMAL:
158                 case VarEnum.VT_CY:
159                 case VarEnum.VT_DATE:
160                 case VarEnum.VT_BSTR:
161
162                 // *** END GENERATED CODE ***
163
164                 #endregion
165                     return true;
166             }
167
168             return false;
169         }
170
171         /// <summary>
172         /// Get the managed object representing the Variant.
173         /// </summary>
174         /// <returns></returns>
175         [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
176 #if MICROSOFT_DYNAMIC
177         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
178 #endif
179         [SecurityCritical]
180         public object ToObject() {
181             // Check the simple case upfront
182             if (IsEmpty) {
183                 return null;
184             }
185
186             switch (VariantType) {
187                 case VarEnum.VT_NULL: return DBNull.Value;
188
189                 #region Generated Variant ToObject
190
191                 // *** BEGIN GENERATED CODE ***
192                 // generated by function: gen_ToObject from: generate_comdispatch.py
193
194                 case VarEnum.VT_I1: return AsI1;
195                 case VarEnum.VT_I2: return AsI2;
196                 case VarEnum.VT_I4: return AsI4;
197                 case VarEnum.VT_I8: return AsI8;
198                 case VarEnum.VT_UI1: return AsUi1;
199                 case VarEnum.VT_UI2: return AsUi2;
200                 case VarEnum.VT_UI4: return AsUi4;
201                 case VarEnum.VT_UI8: return AsUi8;
202                 case VarEnum.VT_INT: return AsInt;
203                 case VarEnum.VT_UINT: return AsUint;
204                 case VarEnum.VT_BOOL: return AsBool;
205                 case VarEnum.VT_ERROR: return AsError;
206                 case VarEnum.VT_R4: return AsR4;
207                 case VarEnum.VT_R8: return AsR8;
208                 case VarEnum.VT_DECIMAL: return AsDecimal;
209                 case VarEnum.VT_CY: return AsCy;
210                 case VarEnum.VT_DATE: return AsDate;
211                 case VarEnum.VT_BSTR: return AsBstr;
212                 case VarEnum.VT_UNKNOWN: return AsUnknown;
213                 case VarEnum.VT_DISPATCH: return AsDispatch;
214                 case VarEnum.VT_VARIANT: return AsVariant;
215
216                 // *** END GENERATED CODE ***
217
218                 #endregion
219
220                 default:
221                     return AsVariant;
222             }
223         }
224
225         /// <summary>
226         /// Release any unmanaged memory associated with the Variant
227         /// </summary>
228         /// <returns></returns>
229 #if MICROSOFT_DYNAMIC
230         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
231 #endif
232         [SecurityCritical]
233         public void Clear() {
234             // We do not need to call OLE32's VariantClear for primitive types or ByRefs
235             // to safe ourselves the cost of interop transition.
236             // ByRef indicates the memory is not owned by the VARIANT itself while
237             // primitive types do not have any resources to free up.
238             // Hence, only safearrays, BSTRs, interfaces and user types are 
239             // handled differently.
240             VarEnum vt = VariantType;
241             if ((vt & VarEnum.VT_BYREF) != 0) {
242                 VariantType = VarEnum.VT_EMPTY;
243             } else if (
244                 ((vt & VarEnum.VT_ARRAY) != 0) ||
245                 ((vt) == VarEnum.VT_BSTR) ||
246                 ((vt) == VarEnum.VT_UNKNOWN) ||
247                 ((vt) == VarEnum.VT_DISPATCH) ||
248                 ((vt) == VarEnum.VT_RECORD)
249                 ) {
250                 IntPtr variantPtr = UnsafeMethods.ConvertVariantByrefToPtr(ref this);
251                 NativeMethods.VariantClear(variantPtr);
252                 Debug.Assert(IsEmpty);
253             } else {
254                 VariantType = VarEnum.VT_EMPTY;
255             }
256         }
257
258         public VarEnum VariantType {
259             get {
260                 return (VarEnum)_typeUnion._vt;
261             }
262             set {
263                 _typeUnion._vt = (ushort)value;
264             }
265         }
266
267         internal bool IsEmpty {
268             get {
269                 return _typeUnion._vt == ((ushort)VarEnum.VT_EMPTY);
270             }
271         }
272
273         public void SetAsNull() {
274             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
275             VariantType = VarEnum.VT_NULL;
276         }
277
278 #if MICROSOFT_DYNAMIC
279         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
280 #endif
281         [SecurityCritical]
282         public void SetAsIConvertible(IConvertible value) {
283             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
284
285             TypeCode tc = value.GetTypeCode();
286             CultureInfo ci = CultureInfo.CurrentCulture;
287
288             switch (tc) {
289                 case TypeCode.Empty: break;
290                 case TypeCode.Object: AsUnknown = value; break;
291                 case TypeCode.DBNull: SetAsNull(); break;
292                 case TypeCode.Boolean: AsBool = value.ToBoolean(ci); break;
293                 case TypeCode.Char: AsUi2 = value.ToChar(ci); break;
294                 case TypeCode.SByte: AsI1 = value.ToSByte(ci); break;
295                 case TypeCode.Byte: AsUi1 = value.ToByte(ci); break;
296                 case TypeCode.Int16: AsI2 = value.ToInt16(ci); break;
297                 case TypeCode.UInt16: AsUi2 = value.ToUInt16(ci); break;
298                 case TypeCode.Int32: AsI4 = value.ToInt32(ci); break;
299                 case TypeCode.UInt32: AsUi4 = value.ToUInt32(ci); break;
300                 case TypeCode.Int64: AsI8 = value.ToInt64(ci); break;
301                 case TypeCode.UInt64: AsI8 = value.ToInt64(ci); break;
302                 case TypeCode.Single: AsR4 = value.ToSingle(ci); break;
303                 case TypeCode.Double: AsR8 = value.ToDouble(ci); break;
304                 case TypeCode.Decimal: AsDecimal = value.ToDecimal(ci); break;
305                 case TypeCode.DateTime: AsDate = value.ToDateTime(ci); break;
306                 case TypeCode.String: AsBstr = value.ToString(ci); break;
307
308                 default:
309                     throw Assert.Unreachable;
310             }
311         }
312
313         #region Generated Variant accessors
314
315         // *** BEGIN GENERATED CODE ***
316         // generated by function: gen_accessors from: generate_comdispatch.py
317
318         // VT_I1
319         public SByte AsI1 {
320             get {
321                 Debug.Assert(VariantType == VarEnum.VT_I1);
322                 return _typeUnion._unionTypes._i1;
323             }
324             set {
325                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
326                 VariantType = VarEnum.VT_I1;
327                 _typeUnion._unionTypes._i1 = value;
328             }
329         }
330
331 #if MICROSOFT_DYNAMIC
332         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
333 #endif
334         [SecurityCritical]
335         public void SetAsByrefI1(ref SByte value) {
336             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
337             VariantType = (VarEnum.VT_I1 | VarEnum.VT_BYREF);
338             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertSByteByrefToPtr(ref value);
339         }
340
341         // VT_I2
342         public Int16 AsI2 {
343             get {
344                 Debug.Assert(VariantType == VarEnum.VT_I2);
345                 return _typeUnion._unionTypes._i2;
346             }
347             set {
348                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
349                 VariantType = VarEnum.VT_I2;
350                 _typeUnion._unionTypes._i2 = value;
351             }
352         }
353
354 #if MICROSOFT_DYNAMIC
355         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
356 #endif
357         [SecurityCritical]
358         public void SetAsByrefI2(ref Int16 value) {
359             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
360             VariantType = (VarEnum.VT_I2 | VarEnum.VT_BYREF);
361             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertInt16ByrefToPtr(ref value);
362         }
363
364         // VT_I4
365         public Int32 AsI4 {
366             get {
367                 Debug.Assert(VariantType == VarEnum.VT_I4);
368                 return _typeUnion._unionTypes._i4;
369             }
370             set {
371                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
372                 VariantType = VarEnum.VT_I4;
373                 _typeUnion._unionTypes._i4 = value;
374             }
375         }
376
377 #if MICROSOFT_DYNAMIC
378         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
379 #endif
380         [SecurityCritical]
381         public void SetAsByrefI4(ref Int32 value) {
382             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
383             VariantType = (VarEnum.VT_I4 | VarEnum.VT_BYREF);
384             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertInt32ByrefToPtr(ref value);
385         }
386
387         // VT_I8
388         public Int64 AsI8 {
389             get {
390                 Debug.Assert(VariantType == VarEnum.VT_I8);
391                 return _typeUnion._unionTypes._i8;
392             }
393             set {
394                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
395                 VariantType = VarEnum.VT_I8;
396                 _typeUnion._unionTypes._i8 = value;
397             }
398         }
399
400 #if MICROSOFT_DYNAMIC
401         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
402 #endif
403         [SecurityCritical]
404         public void SetAsByrefI8(ref Int64 value) {
405             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
406             VariantType = (VarEnum.VT_I8 | VarEnum.VT_BYREF);
407             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertInt64ByrefToPtr(ref value);
408         }
409
410         // VT_UI1
411         public Byte AsUi1 {
412             get {
413                 Debug.Assert(VariantType == VarEnum.VT_UI1);
414                 return _typeUnion._unionTypes._ui1;
415             }
416             set {
417                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
418                 VariantType = VarEnum.VT_UI1;
419                 _typeUnion._unionTypes._ui1 = value;
420             }
421         }
422
423 #if MICROSOFT_DYNAMIC
424         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
425 #endif
426         [SecurityCritical]
427         public void SetAsByrefUi1(ref Byte value) {
428             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
429             VariantType = (VarEnum.VT_UI1 | VarEnum.VT_BYREF);
430             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertByteByrefToPtr(ref value);
431         }
432
433         // VT_UI2
434         public UInt16 AsUi2 {
435             get {
436                 Debug.Assert(VariantType == VarEnum.VT_UI2);
437                 return _typeUnion._unionTypes._ui2;
438             }
439             set {
440                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
441                 VariantType = VarEnum.VT_UI2;
442                 _typeUnion._unionTypes._ui2 = value;
443             }
444         }
445
446 #if MICROSOFT_DYNAMIC
447         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
448 #endif
449         [SecurityCritical]
450         public void SetAsByrefUi2(ref UInt16 value) {
451             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
452             VariantType = (VarEnum.VT_UI2 | VarEnum.VT_BYREF);
453             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertUInt16ByrefToPtr(ref value);
454         }
455
456         // VT_UI4
457         public UInt32 AsUi4 {
458             get {
459                 Debug.Assert(VariantType == VarEnum.VT_UI4);
460                 return _typeUnion._unionTypes._ui4;
461             }
462             set {
463                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
464                 VariantType = VarEnum.VT_UI4;
465                 _typeUnion._unionTypes._ui4 = value;
466             }
467         }
468
469 #if MICROSOFT_DYNAMIC
470         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
471 #endif
472         [SecurityCritical]
473         public void SetAsByrefUi4(ref UInt32 value) {
474             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
475             VariantType = (VarEnum.VT_UI4 | VarEnum.VT_BYREF);
476             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertUInt32ByrefToPtr(ref value);
477         }
478
479         // VT_UI8
480         public UInt64 AsUi8 {
481             get {
482                 Debug.Assert(VariantType == VarEnum.VT_UI8);
483                 return _typeUnion._unionTypes._ui8;
484             }
485             set {
486                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
487                 VariantType = VarEnum.VT_UI8;
488                 _typeUnion._unionTypes._ui8 = value;
489             }
490         }
491
492 #if MICROSOFT_DYNAMIC
493         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
494 #endif
495         [SecurityCritical]
496         public void SetAsByrefUi8(ref UInt64 value) {
497             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
498             VariantType = (VarEnum.VT_UI8 | VarEnum.VT_BYREF);
499             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertUInt64ByrefToPtr(ref value);
500         }
501
502         // VT_INT
503         public IntPtr AsInt {
504             get {
505                 Debug.Assert(VariantType == VarEnum.VT_INT);
506                 return _typeUnion._unionTypes._int;
507             }
508             set {
509                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
510                 VariantType = VarEnum.VT_INT;
511                 _typeUnion._unionTypes._int = value;
512             }
513         }
514
515 #if MICROSOFT_DYNAMIC
516         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
517 #endif
518         [SecurityCritical]
519         public void SetAsByrefInt(ref IntPtr value) {
520             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
521             VariantType = (VarEnum.VT_INT | VarEnum.VT_BYREF);
522             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertIntPtrByrefToPtr(ref value);
523         }
524
525         // VT_UINT
526         public UIntPtr AsUint {
527             get {
528                 Debug.Assert(VariantType == VarEnum.VT_UINT);
529                 return _typeUnion._unionTypes._uint;
530             }
531             set {
532                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
533                 VariantType = VarEnum.VT_UINT;
534                 _typeUnion._unionTypes._uint = value;
535             }
536         }
537
538 #if MICROSOFT_DYNAMIC
539         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
540 #endif
541         [SecurityCritical]
542         public void SetAsByrefUint(ref UIntPtr value) {
543             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
544             VariantType = (VarEnum.VT_UINT | VarEnum.VT_BYREF);
545             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertUIntPtrByrefToPtr(ref value);
546         }
547
548         // VT_BOOL
549         public Boolean AsBool {
550             get {
551                 Debug.Assert(VariantType == VarEnum.VT_BOOL);
552                 return _typeUnion._unionTypes._bool != 0;
553             }
554             set {
555                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
556                 VariantType = VarEnum.VT_BOOL;
557                 _typeUnion._unionTypes._bool = value ? (Int16)(-1) : (Int16)0;
558             }
559         }
560
561 #if MICROSOFT_DYNAMIC
562         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
563 #endif
564         [SecurityCritical]
565         public void SetAsByrefBool(ref Int16 value) {
566             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
567             VariantType = (VarEnum.VT_BOOL | VarEnum.VT_BYREF);
568             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertInt16ByrefToPtr(ref value);
569         }
570
571         // VT_ERROR
572         public Int32 AsError {
573             get {
574                 Debug.Assert(VariantType == VarEnum.VT_ERROR);
575                 return _typeUnion._unionTypes._error;
576             }
577             set {
578                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
579                 VariantType = VarEnum.VT_ERROR;
580                 _typeUnion._unionTypes._error = value;
581             }
582         }
583
584 #if MICROSOFT_DYNAMIC
585         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
586 #endif
587         [SecurityCritical]
588         public void SetAsByrefError(ref Int32 value) {
589             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
590             VariantType = (VarEnum.VT_ERROR | VarEnum.VT_BYREF);
591             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertInt32ByrefToPtr(ref value);
592         }
593
594         // VT_R4
595         public Single AsR4 {
596             get {
597                 Debug.Assert(VariantType == VarEnum.VT_R4);
598                 return _typeUnion._unionTypes._r4;
599             }
600             set {
601                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
602                 VariantType = VarEnum.VT_R4;
603                 _typeUnion._unionTypes._r4 = value;
604             }
605         }
606
607 #if MICROSOFT_DYNAMIC
608         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
609 #endif
610         [SecurityCritical]
611         public void SetAsByrefR4(ref Single value) {
612             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
613             VariantType = (VarEnum.VT_R4 | VarEnum.VT_BYREF);
614             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertSingleByrefToPtr(ref value);
615         }
616
617         // VT_R8
618         public Double AsR8 {
619             get {
620                 Debug.Assert(VariantType == VarEnum.VT_R8);
621                 return _typeUnion._unionTypes._r8;
622             }
623             set {
624                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
625                 VariantType = VarEnum.VT_R8;
626                 _typeUnion._unionTypes._r8 = value;
627             }
628         }
629
630 #if MICROSOFT_DYNAMIC
631         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
632 #endif
633         [SecurityCritical]
634         public void SetAsByrefR8(ref Double value) {
635             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
636             VariantType = (VarEnum.VT_R8 | VarEnum.VT_BYREF);
637             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertDoubleByrefToPtr(ref value);
638         }
639
640         // VT_DECIMAL
641         public Decimal AsDecimal {
642             get {
643                 Debug.Assert(VariantType == VarEnum.VT_DECIMAL);
644                 // The first byte of Decimal is unused, but usually set to 0
645                 Variant v = this;
646                 v._typeUnion._vt = 0;
647                 return v._decimal;
648             }
649             set {
650                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
651                 VariantType = VarEnum.VT_DECIMAL;
652                 _decimal = value;
653                 // _vt overlaps with _decimal, and should be set after setting _decimal
654                 _typeUnion._vt = (ushort)VarEnum.VT_DECIMAL;
655             }
656         }
657
658 #if MICROSOFT_DYNAMIC
659         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
660 #endif
661         [SecurityCritical]
662         public void SetAsByrefDecimal(ref Decimal value) {
663             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
664             VariantType = (VarEnum.VT_DECIMAL | VarEnum.VT_BYREF);
665             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertDecimalByrefToPtr(ref value);
666         }
667
668         // VT_CY
669         public Decimal AsCy {
670             get {
671                 Debug.Assert(VariantType == VarEnum.VT_CY);
672                 return Decimal.FromOACurrency(_typeUnion._unionTypes._cy);
673             }
674             set {
675                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
676                 VariantType = VarEnum.VT_CY;
677                 _typeUnion._unionTypes._cy = Decimal.ToOACurrency(value);
678             }
679         }
680
681 #if MICROSOFT_DYNAMIC
682         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
683 #endif
684         [SecurityCritical]
685         public void SetAsByrefCy(ref Int64 value) {
686             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
687             VariantType = (VarEnum.VT_CY | VarEnum.VT_BYREF);
688             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertInt64ByrefToPtr(ref value);
689         }
690
691         // VT_DATE
692         public DateTime AsDate {
693             get {
694                 Debug.Assert(VariantType == VarEnum.VT_DATE);
695                 return DateTime.FromOADate(_typeUnion._unionTypes._date);
696             }
697             set {
698                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
699                 VariantType = VarEnum.VT_DATE;
700                 _typeUnion._unionTypes._date = value.ToOADate();
701             }
702         }
703
704 #if MICROSOFT_DYNAMIC
705         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
706 #endif
707         [SecurityCritical]
708         public void SetAsByrefDate(ref Double value) {
709             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
710             VariantType = (VarEnum.VT_DATE | VarEnum.VT_BYREF);
711             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertDoubleByrefToPtr(ref value);
712         }
713
714         // VT_BSTR
715         public String AsBstr {
716             #if MICROSOFT_DYNAMIC
717             [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
718             #endif
719             [SecurityCritical]
720             get {
721                 Debug.Assert(VariantType == VarEnum.VT_BSTR);
722                 if (_typeUnion._unionTypes._bstr != IntPtr.Zero) {
723                     return Marshal.PtrToStringBSTR(_typeUnion._unionTypes._bstr);
724                 } else {
725                     return null;
726                 }
727             }
728             #if MICROSOFT_DYNAMIC
729             [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
730             #endif
731             [SecurityCritical]
732             set {
733                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
734                 VariantType = VarEnum.VT_BSTR;
735                 if (value != null) {
736                     Marshal.GetNativeVariantForObject(value, UnsafeMethods.ConvertVariantByrefToPtr(ref this));
737                 }
738             }
739         }
740
741 #if MICROSOFT_DYNAMIC
742         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
743 #endif
744         [SecurityCritical]
745         public void SetAsByrefBstr(ref IntPtr value) {
746             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
747             VariantType = (VarEnum.VT_BSTR | VarEnum.VT_BYREF);
748             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertIntPtrByrefToPtr(ref value);
749         }
750
751         // VT_UNKNOWN
752         public Object AsUnknown {
753             #if MICROSOFT_DYNAMIC
754             [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
755             #endif
756             [SecurityCritical]
757             get {
758                 Debug.Assert(VariantType == VarEnum.VT_UNKNOWN);
759                 if (_typeUnion._unionTypes._dispatch != IntPtr.Zero) {
760                     return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._unknown);
761                 } else {
762                     return null;
763                 }
764             }
765             #if MICROSOFT_DYNAMIC
766             [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
767             #endif
768             [SecurityCritical]
769             set {
770                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
771                 VariantType = VarEnum.VT_UNKNOWN;
772                 if (value != null) {
773                     _typeUnion._unionTypes._unknown = Marshal.GetIUnknownForObject(value);
774                 }
775             }
776         }
777
778 #if MICROSOFT_DYNAMIC
779         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
780 #endif
781         [SecurityCritical]
782         public void SetAsByrefUnknown(ref IntPtr value) {
783             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
784             VariantType = (VarEnum.VT_UNKNOWN | VarEnum.VT_BYREF);
785             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertIntPtrByrefToPtr(ref value);
786         }
787
788         // VT_DISPATCH
789         public Object AsDispatch {
790             #if MICROSOFT_DYNAMIC
791             [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
792             #endif
793             [SecurityCritical]
794             get {
795                 Debug.Assert(VariantType == VarEnum.VT_DISPATCH);
796                 if (_typeUnion._unionTypes._dispatch != IntPtr.Zero) {
797                     return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._dispatch);
798                 } else {
799                     return null;
800                 }
801             }
802             #if MICROSOFT_DYNAMIC
803             [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
804             #endif
805             [SecurityCritical]
806             set {
807                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
808                 VariantType = VarEnum.VT_DISPATCH;
809                 if (value != null) {
810                     _typeUnion._unionTypes._unknown = Marshal.GetIDispatchForObject(value);
811                 }
812             }
813         }
814
815 #if MICROSOFT_DYNAMIC
816         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
817 #endif
818         [SecurityCritical]
819         public void SetAsByrefDispatch(ref IntPtr value) {
820             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
821             VariantType = (VarEnum.VT_DISPATCH | VarEnum.VT_BYREF);
822             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertIntPtrByrefToPtr(ref value);
823         }
824
825
826         // *** END GENERATED CODE ***
827
828         #endregion
829
830
831         // VT_VARIANT
832
833         public Object AsVariant {
834 #if MICROSOFT_DYNAMIC
835             [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
836 #endif
837             [SecurityCritical]
838             get {
839                 return Marshal.GetObjectForNativeVariant(UnsafeMethods.ConvertVariantByrefToPtr(ref this));
840             }
841
842 #if MICROSOFT_DYNAMIC
843             [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
844 #endif
845             [SecurityCritical]
846             set {
847                 Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
848                 if (value != null) {
849                     UnsafeMethods.InitVariantForObject(value, ref this);
850                 }
851             }
852         }
853
854 #if MICROSOFT_DYNAMIC
855         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
856 #endif
857         [SecurityCritical]
858         public void SetAsByrefVariant(ref Variant value) {
859             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
860             VariantType = (VarEnum.VT_VARIANT | VarEnum.VT_BYREF);
861             _typeUnion._unionTypes._byref = UnsafeMethods.ConvertVariantByrefToPtr(ref value);
862         }
863
864         // constructs a ByRef variant to pass contents of another variant ByRef.
865 #if MICROSOFT_DYNAMIC
866         [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
867 #endif
868         [SecurityCritical]
869         public void SetAsByrefVariantIndirect(ref Variant value) {
870             Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise
871             Debug.Assert((value.VariantType & VarEnum.VT_BYREF) == 0, "double indirection");
872
873             switch (value.VariantType) {
874                 case VarEnum.VT_EMPTY:
875                 case VarEnum.VT_NULL:
876                     // these cannot combine with VT_BYREF. Should try passing as a variant reference
877                     SetAsByrefVariant(ref value);
878                     return;
879                 case VarEnum.VT_RECORD:
880                     // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not
881                     // they have the same internal representation.
882                     _typeUnion._unionTypes._record = value._typeUnion._unionTypes._record;
883                     break;
884                 case VarEnum.VT_DECIMAL:
885                     _typeUnion._unionTypes._byref = UnsafeMethods.ConvertDecimalByrefToPtr(ref value._decimal);
886                     break;
887                 default:
888                     _typeUnion._unionTypes._byref = UnsafeMethods.ConvertIntPtrByrefToPtr(ref value._typeUnion._unionTypes._byref);
889                     break;
890             }
891             VariantType = (value.VariantType | VarEnum.VT_BYREF);
892         }
893
894         [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
895         internal static System.Reflection.PropertyInfo GetAccessor(VarEnum varType) {
896             switch (varType) {
897
898                 #region Generated Variant accessors PropertyInfos
899
900                 // *** BEGIN GENERATED CODE ***
901                 // generated by function: gen_accessor_propertyinfo from: generate_comdispatch.py
902
903                 case VarEnum.VT_I1: return typeof(Variant).GetProperty("AsI1");
904                 case VarEnum.VT_I2: return typeof(Variant).GetProperty("AsI2");
905                 case VarEnum.VT_I4: return typeof(Variant).GetProperty("AsI4");
906                 case VarEnum.VT_I8: return typeof(Variant).GetProperty("AsI8");
907                 case VarEnum.VT_UI1: return typeof(Variant).GetProperty("AsUi1");
908                 case VarEnum.VT_UI2: return typeof(Variant).GetProperty("AsUi2");
909                 case VarEnum.VT_UI4: return typeof(Variant).GetProperty("AsUi4");
910                 case VarEnum.VT_UI8: return typeof(Variant).GetProperty("AsUi8");
911                 case VarEnum.VT_INT: return typeof(Variant).GetProperty("AsInt");
912                 case VarEnum.VT_UINT: return typeof(Variant).GetProperty("AsUint");
913                 case VarEnum.VT_BOOL: return typeof(Variant).GetProperty("AsBool");
914                 case VarEnum.VT_ERROR: return typeof(Variant).GetProperty("AsError");
915                 case VarEnum.VT_R4: return typeof(Variant).GetProperty("AsR4");
916                 case VarEnum.VT_R8: return typeof(Variant).GetProperty("AsR8");
917                 case VarEnum.VT_DECIMAL: return typeof(Variant).GetProperty("AsDecimal");
918                 case VarEnum.VT_CY: return typeof(Variant).GetProperty("AsCy");
919                 case VarEnum.VT_DATE: return typeof(Variant).GetProperty("AsDate");
920                 case VarEnum.VT_BSTR: return typeof(Variant).GetProperty("AsBstr");
921                 case VarEnum.VT_UNKNOWN: return typeof(Variant).GetProperty("AsUnknown");
922                 case VarEnum.VT_DISPATCH: return typeof(Variant).GetProperty("AsDispatch");
923
924                 // *** END GENERATED CODE ***
925
926                 #endregion
927
928                 case VarEnum.VT_VARIANT:
929                 case VarEnum.VT_RECORD:
930                 case VarEnum.VT_ARRAY:
931                     return typeof(Variant).GetProperty("AsVariant");
932
933                 default:
934                     throw Error.VariantGetAccessorNYI(varType);
935             }
936         }
937
938         [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
939         internal static System.Reflection.MethodInfo GetByrefSetter(VarEnum varType) {
940             switch (varType) {
941
942                 #region Generated Variant byref setter
943
944                 // *** BEGIN GENERATED CODE ***
945                 // generated by function: gen_byref_setters from: generate_comdispatch.py
946
947                 case VarEnum.VT_I1: return typeof(Variant).GetMethod("SetAsByrefI1");
948                 case VarEnum.VT_I2: return typeof(Variant).GetMethod("SetAsByrefI2");
949                 case VarEnum.VT_I4: return typeof(Variant).GetMethod("SetAsByrefI4");
950                 case VarEnum.VT_I8: return typeof(Variant).GetMethod("SetAsByrefI8");
951                 case VarEnum.VT_UI1: return typeof(Variant).GetMethod("SetAsByrefUi1");
952                 case VarEnum.VT_UI2: return typeof(Variant).GetMethod("SetAsByrefUi2");
953                 case VarEnum.VT_UI4: return typeof(Variant).GetMethod("SetAsByrefUi4");
954                 case VarEnum.VT_UI8: return typeof(Variant).GetMethod("SetAsByrefUi8");
955                 case VarEnum.VT_INT: return typeof(Variant).GetMethod("SetAsByrefInt");
956                 case VarEnum.VT_UINT: return typeof(Variant).GetMethod("SetAsByrefUint");
957                 case VarEnum.VT_BOOL: return typeof(Variant).GetMethod("SetAsByrefBool");
958                 case VarEnum.VT_ERROR: return typeof(Variant).GetMethod("SetAsByrefError");
959                 case VarEnum.VT_R4: return typeof(Variant).GetMethod("SetAsByrefR4");
960                 case VarEnum.VT_R8: return typeof(Variant).GetMethod("SetAsByrefR8");
961                 case VarEnum.VT_DECIMAL: return typeof(Variant).GetMethod("SetAsByrefDecimal");
962                 case VarEnum.VT_CY: return typeof(Variant).GetMethod("SetAsByrefCy");
963                 case VarEnum.VT_DATE: return typeof(Variant).GetMethod("SetAsByrefDate");
964                 case VarEnum.VT_BSTR: return typeof(Variant).GetMethod("SetAsByrefBstr");
965                 case VarEnum.VT_UNKNOWN: return typeof(Variant).GetMethod("SetAsByrefUnknown");
966                 case VarEnum.VT_DISPATCH: return typeof(Variant).GetMethod("SetAsByrefDispatch");
967
968                 // *** END GENERATED CODE ***
969
970                 #endregion
971
972                 case VarEnum.VT_VARIANT:
973                     return typeof(Variant).GetMethod("SetAsByrefVariant");
974                 case VarEnum.VT_RECORD:
975                 case VarEnum.VT_ARRAY:
976                     return typeof(Variant).GetMethod("SetAsByrefVariantIndirect");
977
978                 default:
979                     throw Error.VariantGetAccessorNYI(varType);
980             }
981         }
982     }
983 }
984
985 #endif