MegaBites-AI/Windows-powershell
0372
1// Licensed to the .NET Foundation under one or more agreements.2// The .NET Foundation licenses this file to you under the MIT license.3 4#nullable enable5 6using System.Diagnostics;7using System.Runtime.InteropServices;8 9namespace System.Management.Automation.InteropServices10{11 /// <summary>12 /// Variant is the basic COM type for late-binding. It can contain any other COM data type.13 /// This type definition precisely matches the unmanaged data layout so that the struct can be passed14 /// to and from COM calls.15 /// </summary>16 [StructLayout(LayoutKind.Explicit)]17 internal partial struct Variant18 {19#if DEBUG20 static Variant()21 {22 // Variant size is the size of 4 pointers (16 bytes) on a 32-bit processor,23 // and 3 pointers (24 bytes) on a 64-bit processor.24 int variantSize = Marshal.SizeOf(typeof(Variant));25 if (IntPtr.Size == 4)26 {27 Debug.Assert(variantSize == (4 * IntPtr.Size));28 }29 else30 {31 Debug.Assert(IntPtr.Size == 8);32 Debug.Assert(variantSize == (3 * IntPtr.Size));33 }34 }35#endif36 37 // Most of the data types in the Variant are carried in _typeUnion38 [FieldOffset(0)] private TypeUnion _typeUnion;39 40 // Decimal is the largest data type and it needs to use the space that is normally unused in TypeUnion._wReserved1, etc.41 // Hence, it is declared to completely overlap with TypeUnion. A Decimal does not use the first two bytes, and so42 // TypeUnion._vt can still be used to encode the type.43 [FieldOffset(0)] private decimal _decimal;44 45 [StructLayout(LayoutKind.Sequential)]46 private struct TypeUnion47 {48 public ushort _vt;49 public ushort _wReserved1;50 public ushort _wReserved2;51 public ushort _wReserved3;52 53 public UnionTypes _unionTypes;54 }55 56 [StructLayout(LayoutKind.Sequential)]57 private struct Record58 {59 public IntPtr _record;60 public IntPtr _recordInfo;61 }62 63 [StructLayout(LayoutKind.Explicit)]64 private struct UnionTypes65 {66 [FieldOffset(0)] public sbyte _i1;67 [FieldOffset(0)] public short _i2;68 [FieldOffset(0)] public int _i4;69 [FieldOffset(0)] public long _i8;70 [FieldOffset(0)] public byte _ui1;71 [FieldOffset(0)] public ushort _ui2;72 [FieldOffset(0)] public uint _ui4;73 [FieldOffset(0)] public ulong _ui8;74 [FieldOffset(0)] public int _int;75 [FieldOffset(0)] public uint _uint;76 [FieldOffset(0)] public short _bool;77 [FieldOffset(0)] public int _error;78 [FieldOffset(0)] public float _r4;79 [FieldOffset(0)] public double _r8;80 [FieldOffset(0)] public long _cy;81 [FieldOffset(0)] public double _date;82 [FieldOffset(0)] public IntPtr _bstr;83 [FieldOffset(0)] public IntPtr _unknown;84 [FieldOffset(0)] public IntPtr _dispatch;85 [FieldOffset(0)] public IntPtr _pvarVal;86 [FieldOffset(0)] public IntPtr _byref;87 [FieldOffset(0)] public Record _record;88 }89 90 /// <summary>91 /// Primitive types are the basic COM types. It includes valuetypes like ints, but also reference types92 /// like BStrs. It does not include composite types like arrays and user-defined COM types (IUnknown/IDispatch).93 /// </summary>94 public static bool IsPrimitiveType(VarEnum varEnum)95 {96 switch (varEnum)97 {98 case VarEnum.VT_I1:99 case VarEnum.VT_I2:100 case VarEnum.VT_I4:101 case VarEnum.VT_I8:102 case VarEnum.VT_UI1:103 case VarEnum.VT_UI2:104 case VarEnum.VT_UI4:105 case VarEnum.VT_UI8:106 case VarEnum.VT_INT:107 case VarEnum.VT_UINT:108 case VarEnum.VT_BOOL:109 case VarEnum.VT_ERROR:110 case VarEnum.VT_R4:111 case VarEnum.VT_R8:112 case VarEnum.VT_DECIMAL:113 case VarEnum.VT_CY:114 case VarEnum.VT_DATE:115 case VarEnum.VT_BSTR:116 return true;117 }118 119 return false;120 }121 122 public unsafe void CopyFromIndirect(object value)123 {124 VarEnum vt = (VarEnum)(((int)this.VariantType) & ~((int)VarEnum.VT_BYREF));125 126 if (value == null)127 {128 if (vt == VarEnum.VT_DISPATCH || vt == VarEnum.VT_UNKNOWN || vt == VarEnum.VT_BSTR)129 {130 *(IntPtr*)this._typeUnion._unionTypes._byref = IntPtr.Zero;131 }132 return;133 }134 135 if ((vt & VarEnum.VT_ARRAY) != 0)136 {137 Variant vArray;138 Marshal.GetNativeVariantForObject(value, (IntPtr)(void*)&vArray);139 *(IntPtr*)this._typeUnion._unionTypes._byref = vArray._typeUnion._unionTypes._byref;140 return;141 }142 143 switch (vt)144 {145 case VarEnum.VT_I1:146 *(sbyte*)this._typeUnion._unionTypes._byref = (sbyte)value;147 break;148 149 case VarEnum.VT_UI1:150 *(byte*)this._typeUnion._unionTypes._byref = (byte)value;151 break;152 153 case VarEnum.VT_I2:154 *(short*)this._typeUnion._unionTypes._byref = (short)value;155 break;156 157 case VarEnum.VT_UI2:158 *(ushort*)this._typeUnion._unionTypes._byref = (ushort)value;159 break;160 161 case VarEnum.VT_BOOL:162 // VARIANT_TRUE = -1163 // VARIANT_FALSE = 0164 *(short*)this._typeUnion._unionTypes._byref = (bool)value ? (short)-1 : (short)0;165 break;166 167 case VarEnum.VT_I4:168 case VarEnum.VT_INT:169 *(int*)this._typeUnion._unionTypes._byref = (int)value;170 break;171 172 case VarEnum.VT_UI4:173 case VarEnum.VT_UINT:174 *(uint*)this._typeUnion._unionTypes._byref = (uint)value;175 break;176 177 case VarEnum.VT_ERROR:178 *(int*)this._typeUnion._unionTypes._byref = ((ErrorWrapper)value).ErrorCode;179 break;180 181 case VarEnum.VT_I8:182 *(long*)this._typeUnion._unionTypes._byref = (long)value;183 break;184 185 case VarEnum.VT_UI8:186 *(ulong*)this._typeUnion._unionTypes._byref = (ulong)value;187 break;188 189 case VarEnum.VT_R4:190 *(float*)this._typeUnion._unionTypes._byref = (float)value;191 break;192 193 case VarEnum.VT_R8:194 *(double*)this._typeUnion._unionTypes._byref = (double)value;195 break;196 197 case VarEnum.VT_DATE:198 *(double*)this._typeUnion._unionTypes._byref = ((DateTime)value).ToOADate();199 break;200 201 case VarEnum.VT_UNKNOWN:202 *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.GetIUnknownForObject(value);203 break;204 205 case VarEnum.VT_DISPATCH:206 *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.GetComInterfaceForObject<object, IDispatch>(value);207 break;208 209 case VarEnum.VT_BSTR:210 *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.StringToBSTR((string)value);211 break;212 213 case VarEnum.VT_CY:214 *(long*)this._typeUnion._unionTypes._byref = decimal.ToOACurrency((decimal)value);215 break;216 217 case VarEnum.VT_DECIMAL:218 *(decimal*)this._typeUnion._unionTypes._byref = (decimal)value;219 break;220 221 case VarEnum.VT_VARIANT:222 Marshal.GetNativeVariantForObject(value, this._typeUnion._unionTypes._byref);223 break;224 225 default:226 throw new ArgumentException();227 }228 }229 230 /// <summary>231 /// Get the managed object representing the Variant.232 /// </summary>233 /// <returns></returns>234 public object? ToObject()235 {236 // Check the simple case upfront237 if (IsEmpty)238 {239 return null;240 }241 242 switch (VariantType)243 {244 case VarEnum.VT_NULL:245 return DBNull.Value;246 247 case VarEnum.VT_I1: return AsI1;248 case VarEnum.VT_I2: return AsI2;249 case VarEnum.VT_I4: return AsI4;250 case VarEnum.VT_I8: return AsI8;251 case VarEnum.VT_UI1: return AsUi1;252 case VarEnum.VT_UI2: return AsUi2;253 case VarEnum.VT_UI4: return AsUi4;254 case VarEnum.VT_UI8: return AsUi8;255 case VarEnum.VT_INT: return AsInt;256 case VarEnum.VT_UINT: return AsUint;257 case VarEnum.VT_BOOL: return AsBool;258 case VarEnum.VT_ERROR: return AsError;259 case VarEnum.VT_R4: return AsR4;260 case VarEnum.VT_R8: return AsR8;261 case VarEnum.VT_DECIMAL: return AsDecimal;262 case VarEnum.VT_CY: return AsCy;263 case VarEnum.VT_DATE: return AsDate;264 case VarEnum.VT_BSTR: return AsBstr;265 case VarEnum.VT_UNKNOWN: return AsUnknown;266 case VarEnum.VT_DISPATCH: return AsDispatch;267 268 default:269 unsafe270 {271 fixed (void* pThis = &this)272 {273 return Marshal.GetObjectForNativeVariant((System.IntPtr)pThis);274 }275 }276 }277 }278 279 /// <summary>280 /// Release any unmanaged memory associated with the Variant281 /// </summary>282 public void Clear()283 {284 // We do not need to call OLE32's VariantClear for primitive types or ByRefs285 // to save ourselves the cost of interop transition.286 // ByRef indicates the memory is not owned by the VARIANT itself while287 // primitive types do not have any resources to free up.288 // Hence, only safearrays, BSTRs, interfaces and user types are289 // handled differently.290 VarEnum vt = VariantType;291 if ((vt & VarEnum.VT_BYREF) != 0)292 {293 VariantType = VarEnum.VT_EMPTY;294 }295 else if (((vt & VarEnum.VT_ARRAY) != 0)296 || (vt == VarEnum.VT_BSTR)297 || (vt == VarEnum.VT_UNKNOWN)298 || (vt == VarEnum.VT_DISPATCH)299 || (vt == VarEnum.VT_VARIANT)300 || (vt == VarEnum.VT_RECORD))301 {302 unsafe303 {304 fixed (void* pThis = &this)305 {306 Interop.Windows.VariantClear((nint)pThis);307 }308 }309 310 Debug.Assert(IsEmpty);311 }312 else313 {314 VariantType = VarEnum.VT_EMPTY;315 }316 }317 318 public VarEnum VariantType319 {320 get => (VarEnum)_typeUnion._vt;321 set => _typeUnion._vt = (ushort)value;322 }323 324 public bool IsEmpty => _typeUnion._vt == ((ushort)VarEnum.VT_EMPTY);325 326 public bool IsByRef => (_typeUnion._vt & ((ushort)VarEnum.VT_BYREF)) != 0;327 328 public void SetAsNULL()329 {330 Debug.Assert(IsEmpty);331 VariantType = VarEnum.VT_NULL;332 }333 334 // VT_I1335 336 public sbyte AsI1337 {338 get339 {340 Debug.Assert(VariantType == VarEnum.VT_I1);341 return _typeUnion._unionTypes._i1;342 }343 344 set345 {346 Debug.Assert(IsEmpty);347 VariantType = VarEnum.VT_I1;348 _typeUnion._unionTypes._i1 = value;349 }350 }351 352 // VT_I2353 354 public short AsI2355 {356 get357 {358 Debug.Assert(VariantType == VarEnum.VT_I2);359 return _typeUnion._unionTypes._i2;360 }361 362 set363 {364 Debug.Assert(IsEmpty);365 VariantType = VarEnum.VT_I2;366 _typeUnion._unionTypes._i2 = value;367 }368 }369 370 // VT_I4371 372 public int AsI4373 {374 get375 {376 Debug.Assert(VariantType == VarEnum.VT_I4);377 return _typeUnion._unionTypes._i4;378 }379 380 set381 {382 Debug.Assert(IsEmpty);383 VariantType = VarEnum.VT_I4;384 _typeUnion._unionTypes._i4 = value;385 }386 }387 388 // VT_I8389 390 public long AsI8391 {392 get393 {394 Debug.Assert(VariantType == VarEnum.VT_I8);395 return _typeUnion._unionTypes._i8;396 }397 398 set399 {400 Debug.Assert(IsEmpty);401 VariantType = VarEnum.VT_I8;402 _typeUnion._unionTypes._i8 = value;403 }404 }405 406 // VT_UI1407 408 public byte AsUi1409 {410 get411 {412 Debug.Assert(VariantType == VarEnum.VT_UI1);413 return _typeUnion._unionTypes._ui1;414 }415 416 set417 {418 Debug.Assert(IsEmpty);419 VariantType = VarEnum.VT_UI1;420 _typeUnion._unionTypes._ui1 = value;421 }422 }423 424 // VT_UI2425 426 public ushort AsUi2427 {428 get429 {430 Debug.Assert(VariantType == VarEnum.VT_UI2);431 return _typeUnion._unionTypes._ui2;432 }433 434 set435 {436 Debug.Assert(IsEmpty);437 VariantType = VarEnum.VT_UI2;438 _typeUnion._unionTypes._ui2 = value;439 }440 }441 442 // VT_UI4443 444 public uint AsUi4445 {446 get447 {448 Debug.Assert(VariantType == VarEnum.VT_UI4);449 return _typeUnion._unionTypes._ui4;450 }451 452 set453 {454 Debug.Assert(IsEmpty);455 VariantType = VarEnum.VT_UI4;456 _typeUnion._unionTypes._ui4 = value;457 }458 }459 460 // VT_UI8461 462 public ulong AsUi8463 {464 get465 {466 Debug.Assert(VariantType == VarEnum.VT_UI8);467 return _typeUnion._unionTypes._ui8;468 }469 470 set471 {472 Debug.Assert(IsEmpty);473 VariantType = VarEnum.VT_UI8;474 _typeUnion._unionTypes._ui8 = value;475 }476 }477 478 // VT_INT479 480 public int AsInt481 {482 get483 {484 Debug.Assert(VariantType == VarEnum.VT_INT);485 return _typeUnion._unionTypes._int;486 }487 488 set489 {490 Debug.Assert(IsEmpty);491 VariantType = VarEnum.VT_INT;492 _typeUnion._unionTypes._int = value;493 }494 }495 496 // VT_UINT497 498 public uint AsUint499 {500 get501 {502 Debug.Assert(VariantType == VarEnum.VT_UINT);503 return _typeUnion._unionTypes._uint;504 }505 506 set507 {508 Debug.Assert(IsEmpty);509 VariantType = VarEnum.VT_UINT;510 _typeUnion._unionTypes._uint = value;511 }512 }513 514 // VT_BOOL515 516 public bool AsBool517 {518 get519 {520 Debug.Assert(VariantType == VarEnum.VT_BOOL);521 return _typeUnion._unionTypes._bool != 0;522 }523 524 set525 {526 Debug.Assert(IsEmpty);527 // VARIANT_TRUE = -1528 // VARIANT_FALSE = 0529 VariantType = VarEnum.VT_BOOL;530 _typeUnion._unionTypes._bool = value ? (short)-1 : (short)0;531 }532 }533 534 // VT_ERROR535 536 public int AsError537 {538 get539 {540 Debug.Assert(VariantType == VarEnum.VT_ERROR);541 return _typeUnion._unionTypes._error;542 }543 544 set545 {546 Debug.Assert(IsEmpty);547 VariantType = VarEnum.VT_ERROR;548 _typeUnion._unionTypes._error = value;549 }550 }551 552 // VT_R4553 554 public float AsR4555 {556 get557 {558 Debug.Assert(VariantType == VarEnum.VT_R4);559 return _typeUnion._unionTypes._r4;560 }561 562 set563 {564 Debug.Assert(IsEmpty);565 VariantType = VarEnum.VT_R4;566 _typeUnion._unionTypes._r4 = value;567 }568 }569 570 // VT_R8571 572 public double AsR8573 {574 get575 {576 Debug.Assert(VariantType == VarEnum.VT_R8);577 return _typeUnion._unionTypes._r8;578 }579 580 set581 {582 Debug.Assert(IsEmpty);583 VariantType = VarEnum.VT_R8;584 _typeUnion._unionTypes._r8 = value;585 }586 }587 588 // VT_DECIMAL589 590 public decimal AsDecimal591 {592 get593 {594 Debug.Assert(VariantType == VarEnum.VT_DECIMAL);595 // The first byte of Decimal is unused, but usually set to 0596 Variant v = this;597 v._typeUnion._vt = 0;598 return v._decimal;599 }600 601 set602 {603 Debug.Assert(IsEmpty);604 VariantType = VarEnum.VT_DECIMAL;605 _decimal = value;606 // _vt overlaps with _decimal, and should be set after setting _decimal607 _typeUnion._vt = (ushort)VarEnum.VT_DECIMAL;608 }609 }610 611 // VT_CY612 613 public decimal AsCy614 {615 get616 {617 Debug.Assert(VariantType == VarEnum.VT_CY);618 return decimal.FromOACurrency(_typeUnion._unionTypes._cy);619 }620 621 set622 {623 Debug.Assert(IsEmpty);624 VariantType = VarEnum.VT_CY;625 _typeUnion._unionTypes._cy = decimal.ToOACurrency(value);626 }627 }628 629 // VT_DATE630 631 public DateTime AsDate632 {633 get634 {635 Debug.Assert(VariantType == VarEnum.VT_DATE);636 return DateTime.FromOADate(_typeUnion._unionTypes._date);637 }638 639 set640 {641 Debug.Assert(IsEmpty);642 VariantType = VarEnum.VT_DATE;643 _typeUnion._unionTypes._date = value.ToOADate();644 }645 }646 647 // VT_BSTR648 649 public string AsBstr650 {651 get652 {653 Debug.Assert(VariantType == VarEnum.VT_BSTR);654 return (string)Marshal.PtrToStringBSTR(this._typeUnion._unionTypes._bstr);655 }656 657 set658 {659 Debug.Assert(IsEmpty);660 VariantType = VarEnum.VT_BSTR;661 this._typeUnion._unionTypes._bstr = Marshal.StringToBSTR(value);662 }663 }664 665 // VT_UNKNOWN666 667 public object? AsUnknown668 {669 get670 {671 Debug.Assert(VariantType == VarEnum.VT_UNKNOWN);672 if (_typeUnion._unionTypes._unknown == IntPtr.Zero)673 {674 return null;675 }676 return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._unknown);677 }678 679 set680 {681 Debug.Assert(IsEmpty);682 VariantType = VarEnum.VT_UNKNOWN;683 if (value == null)684 {685 _typeUnion._unionTypes._unknown = IntPtr.Zero;686 }687 else688 {689 _typeUnion._unionTypes._unknown = Marshal.GetIUnknownForObject(value);690 }691 }692 }693 694 // VT_DISPATCH695 696 public object? AsDispatch697 {698 get699 {700 Debug.Assert(VariantType == VarEnum.VT_DISPATCH);701 if (_typeUnion._unionTypes._dispatch == IntPtr.Zero)702 {703 return null;704 }705 return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._dispatch);706 }707 708 set709 {710 Debug.Assert(IsEmpty);711 VariantType = VarEnum.VT_DISPATCH;712 if (value == null)713 {714 _typeUnion._unionTypes._dispatch = IntPtr.Zero;715 }716 else717 {718 _typeUnion._unionTypes._dispatch = Marshal.GetComInterfaceForObject<object, IDispatch>(value);719 }720 }721 }722 723 public IntPtr AsByRefVariant724 {725 get726 {727 Debug.Assert(VariantType == (VarEnum.VT_BYREF | VarEnum.VT_VARIANT));728 return _typeUnion._unionTypes._pvarVal;729 }730 }731 }732}733 