diff --git a/PInvoke/Ole/Ole32/PropIdl.PROPVARIANT.cs b/PInvoke/Ole/Ole32/PropIdl.PROPVARIANT.cs
index 078970a0..1c408a43 100644
--- a/PInvoke/Ole/Ole32/PropIdl.PROPVARIANT.cs
+++ b/PInvoke/Ole/Ole32/PropIdl.PROPVARIANT.cs
@@ -18,8 +18,8 @@ namespace Vanara.PInvoke
public static partial class Ole32
{
///
- /// Structure to mimic behavior of VT_BLOB type. "DWORD count of bytes, followed by that many bytes of data. The byte count does not include the four
- /// bytes for the length of the count itself; an empty blob member would have a count of zero, followed by zero bytes."
+ /// Structure to mimic behavior of VT_BLOB type. "DWORD count of bytes, followed by that many bytes of data. The byte count does not
+ /// include the four bytes for the length of the count itself; an empty blob member would have a count of zero, followed by zero bytes."
///
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct BLOB
@@ -47,7 +47,9 @@ namespace Vanara.PInvoke
/// Initializes a new instance of the struct.
/// The clipboard format.
/// A pointer to the data.
- /// Length of the data in bytes. Do not include any length other than that pointed to by .
+ ///
+ /// Length of the data in bytes. Do not include any length other than that pointed to by .
+ ///
public CLIPDATA(int clipFmt, IntPtr dataPtr, int dataLength)
{
cbSize = dataLength + Marshal.SizeOf(typeof(int));
@@ -76,11 +78,14 @@ namespace Vanara.PInvoke
{
case 0:
return "[No data]";
+
case -1:
case -2:
return $"CF={ClipboardFormat}";
+
case -3:
return $"FMTID={FMTID:B}";
+
default:
return $"Name={ClipboardFormatName}";
}
@@ -97,15 +102,15 @@ namespace Vanara.PInvoke
}
///
- /// The PROPVARIANT structure is used in the ReadMultiple and WriteMultiple methods of IPropertyStorage to define the type tag and the value of a
- /// property in a property set.
+ /// The PROPVARIANT structure is used in the ReadMultiple and WriteMultiple methods of IPropertyStorage to define the type tag and
+ /// the value of a property in a property set.
///
- /// The PROPVARIANT structure is also used by the GetValue and SetValue methods of IPropertyStore, which replaces IPropertySetStorage as the primary way
- /// to program item properties in Windows Vista. For more information, see Property Handlers.
+ /// The PROPVARIANT structure is also used by the GetValue and SetValue methods of IPropertyStore, which replaces IPropertySetStorage
+ /// as the primary way to program item properties in Windows Vista. For more information, see Property Handlers.
///
///
- /// There are five members. The first member, the value-type tag, and the last member, the value of the property, are significant. The middle three
- /// members are reserved for future use.
+ /// There are five members. The first member, the value-type tag, and the last member, the value of the property, are significant.
+ /// The middle three members are reserved for future use.
///
///
[StructLayout(LayoutKind.Explicit, Size = 16, Pack = 8)]
@@ -148,7 +153,7 @@ namespace Vanara.PInvoke
/// If not VT_EMPTY, this value will override the inferred value type.
public PROPVARIANT(object obj, VarEnum type = VarEnum.VT_EMPTY)
{
- if (obj == null)
+ if (obj is null)
VarType = type;
else if (obj is PROPVARIANT pv)
PropVariantCopy(this, pv);
@@ -156,11 +161,10 @@ namespace Vanara.PInvoke
SetValue(obj, type);
}
- /// Initializes a new instance of the class from another PROPVARIANT.
- /// An existing instance.
- public PROPVARIANT(PROPVARIANT sourceVar)
+ /// Finalizes an instance of the class.
+ ~PROPVARIANT()
{
- PropVariantCopy(this, sourceVar);
+ Dispose();
}
/// Gets the BLOB value.
@@ -188,14 +192,7 @@ namespace Vanara.PInvoke
public IEnumerable caclipdata => GetVector();
/// Gets the decimal array value.
- public IEnumerable cacy
- {
- get
- {
- foreach (var s in GetVector())
- yield return decimal.FromOACurrency(s);
- }
- }
+ public IEnumerable cacy => GetVector().Select(decimal.FromOACurrency);
/// Gets the DateTime array value.
public IEnumerable cadate => GetVector().Select(DateTime.FromOADate);
@@ -219,7 +216,7 @@ namespace Vanara.PInvoke
public IEnumerable cal => GetVector();
/// Gets the ANSI string array value.
- public IEnumerable calpstr => throw new NotSupportedException(); //GetStringVector();
+ public IEnumerable calpstr => GetStringVector();
/// Gets the Unicode string array value.
public IEnumerable calpwstr => GetStringVector();
@@ -269,6 +266,24 @@ namespace Vanara.PInvoke
/// Gets the int value.
public int intVal => GetRawValue().GetValueOrDefault();
+ //public IntPtr pparray { get { return GetRefValue(); } }
+
+ /// Gets a value indicating whether this instance is by reference.
+ /// true if this instance is null or empty; otherwise, false.
+ public bool IsByRef => vt.IsFlagSet(VARTYPE.VT_BYREF);
+
+ /// Gets a value indicating whether this instance is null or empty.
+ /// true if this instance is null or empty; otherwise, false.
+ public bool IsNullOrEmpty => vt == VARTYPE.VT_EMPTY || vt == VARTYPE.VT_NULL;
+
+ /// Gets a value indicating whether this instance is a string.
+ /// true if this instance is a VT_BSTR or VT_LPWSTR; otherwise, false.
+ public bool IsString => vt == VARTYPE.VT_BSTR || vt == VARTYPE.VT_LPWSTR;
+
+ /// Gets a value indicating whether this instance has a vector type.
+ /// true if this instance is a VT_ARRAY or VT_VECTOR; otherwise, false.
+ public bool IsVector => vt.IsFlagSet(VARTYPE.VT_ARRAY) || vt.IsFlagSet(VARTYPE.VT_VECTOR);
+
/// Gets the short value.
public short iVal => GetRawValue().GetValueOrDefault();
@@ -282,7 +297,7 @@ namespace Vanara.PInvoke
public bool? pboolVal => GetRawValue();
/// Gets the "by value" string value.
- public string pbstrVal => GetString(VarType);
+ public IntPtr pbstrVal => _ptr;
/// Gets the "by value" byte value.
public byte? pbVal => GetRawValue();
@@ -398,132 +413,10 @@ namespace Vanara.PInvoke
/// Gets the uint value.
public uint ulVal => GetRawValue().GetValueOrDefault();
- //public IntPtr pparray { get { return GetRefValue(); } }
-
- /// Gets a value indicating whether this instance is null or empty.
- /// true if this instance is null or empty; otherwise, false.
- public bool IsNullOrEmpty => vt == VARTYPE.VT_EMPTY || vt == VARTYPE.VT_NULL;
-
- /// Gets a value indicating whether this instance is a string.
- /// true if this instance is a VT_BSTR or VT_LPWSTR; otherwise, false.
- public bool IsString => vt == VARTYPE.VT_BSTR || vt == VARTYPE.VT_LPWSTR;
-
- /// Gets a value indicating whether this instance has a vector type.
- /// true if this instance is a VT_ARRAY or VT_VECTOR; otherwise, false.
- public bool IsVector => vt.IsFlagSet(VARTYPE.VT_ARRAY) || vt.IsFlagSet(VARTYPE.VT_VECTOR);
-
/// Gets the value base on the value.
public object Value
{
- get
- {
- if (vt.IsFlagSet(VARTYPE.VT_ARRAY)) return GetSafeArray();
- var isVector = vt.IsFlagSet(VARTYPE.VT_VECTOR);
- var isRef = vt.IsFlagSet(VARTYPE.VT_BYREF);
- var elemType = (VARTYPE)((int)vt & 0xFFF);
- switch (elemType)
- {
- case VARTYPE.VT_NULL:
- return DBNull.Value;
-
- case VARTYPE.VT_I2:
- return isRef ? piVal : (isVector ? cai : (object)iVal);
-
- case VARTYPE.VT_INT:
- case VARTYPE.VT_I4:
- return isRef ? plVal : (isVector ? cal : (object)lVal);
-
- case VARTYPE.VT_BSTR:
- return isRef ? pbstrVal : (isVector ? cabstr : (object)bstrVal);
-
- case VARTYPE.VT_DISPATCH:
- case VARTYPE.VT_UNKNOWN:
- return isVector ? GetVector()?.Select(Marshal.GetObjectForIUnknown) : (isRef ? ppunkVal : punkVal);
-
- case VARTYPE.VT_BOOL:
- return isRef ? pboolVal : (isVector ? cabool : (object)boolVal);
-
- case VARTYPE.VT_I1:
- return isRef ? pcVal : (isVector ? cac : (object)cVal);
-
- case VARTYPE.VT_UI1:
- return isRef ? pbVal : (isVector ? caub : (object)bVal);
-
- case VARTYPE.VT_UI2:
- return isRef ? puiVal : (isVector ? caui : (object)uiVal);
-
- case VARTYPE.VT_UINT:
- case VARTYPE.VT_UI4:
- return isRef ? pulVal : (isVector ? caul : (object)ulVal);
-
- case VARTYPE.VT_ERROR:
- return isRef ? pscode : (isVector ? cascode : (object)scode);
-
- case VARTYPE.VT_I8:
- return isRef ? hVal : (isVector ? cah : (object)hVal);
-
- case VARTYPE.VT_UI8:
- return isRef ? uhVal : (isVector ? cauh : (object)uhVal);
-
- case VARTYPE.VT_HRESULT:
- return isRef
- ? (pulVal.HasValue ? new HRESULT(pulVal.Value) : (HRESULT?)null)
- : (isVector ? caul.Select(u => new HRESULT(u)) : (object)new HRESULT(ulVal));
-
- case VARTYPE.VT_PTR:
- case VARTYPE.VT_RECORD:
- case VARTYPE.VT_USERDEFINED:
- case VARTYPE.VT_VOID:
- return isRef ? IntPtr.Zero : (isVector ? GetVector() : (object)_ptr);
-
- case VARTYPE.VT_LPSTR:
- return isRef ? pszVal : (isVector ? calpstr : (object)pszVal);
-
- case VARTYPE.VT_LPWSTR:
- return isRef ? pwszVal : (isVector ? calpwstr : (object)pwszVal);
-
- case VARTYPE.VT_R8:
- return isRef ? dblVal : (isVector ? cadbl : (object)dblVal);
-
- case VARTYPE.VT_DATE:
- return isRef ? pdate : (isVector ? cadate : (object)date);
-
- case VARTYPE.VT_CY:
- return isRef ? pcyVal : (isVector ? cacy : (object)cyVal);
-
- case VARTYPE.VT_DECIMAL:
- return isRef ? pdecVal : (isVector ? GetVector() : (object)pdecVal.GetValueOrDefault());
-
- case VARTYPE.VT_R4:
- return isRef ? pfltVal : (isVector ? caflt : (object)fltVal);
-
- case VARTYPE.VT_FILETIME:
- return isRef ? filetime : (isVector ? cafiletime : (object)filetime);
-
- case VARTYPE.VT_BLOB:
- return isRef ? _blob : (isVector ? null : (object)_blob);
-
- case VARTYPE.VT_STREAM:
- case VARTYPE.VT_STREAMED_OBJECT:
- return isRef ? pStream : (isVector ? null : pStream);
-
- case VARTYPE.VT_STORAGE:
- case VARTYPE.VT_STORED_OBJECT:
- return isRef ? pStorage : (isVector ? null : pStorage);
-
- case VARTYPE.VT_CF:
- return isRef ? pclipdata : (isVector ? caclipdata : (object)pclipdata);
-
- case VARTYPE.VT_CLSID:
- return isRef ? puuid : (isVector ? cauuid : (object)puuid.GetValueOrDefault());
-
- case VARTYPE.VT_VARIANT:
- return isRef ? pvarVal : (isVector ? GetVector() : (object)pvarVal);
-
- default:
- return null;
- }
- }
+ get => GetValue();
private set => SetValue(value);
}
@@ -531,6 +424,51 @@ namespace Vanara.PInvoke
/// The value type.
public VarEnum VarType { get => (VarEnum)vt; set => vt = (VARTYPE)value; }
+ private bool IsPrimitive
+ {
+ get
+ {
+ switch (vt)
+ {
+ // Signed
+ case VARTYPE.VT_I1:
+ case VARTYPE.VT_I2:
+ case VARTYPE.VT_I4:
+ case VARTYPE.VT_I8:
+ // Unsigned
+ case VARTYPE.VT_UI1:
+ case VARTYPE.VT_UI2:
+ case VARTYPE.VT_UI4:
+ case VARTYPE.VT_UI8:
+ // Converts to int or uint
+ case VARTYPE.VT_BOOL:
+ case VARTYPE.VT_ERROR:
+ case VARTYPE.VT_HRESULT:
+ case VARTYPE.VT_INT:
+ case VARTYPE.VT_UINT:
+ // Floats
+ case VARTYPE.VT_R4:
+ case VARTYPE.VT_R8:
+ // Dates
+ case VARTYPE.VT_DATE:
+ case VARTYPE.VT_FILETIME:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ /// Creates a new instance from a pointer to a VARIANT.
+ /// A pointer to a native in-memory VARIANT.
+ /// A new instance converted from the VARIANT pointer.
+ public static PROPVARIANT FromNativeVariant(IntPtr pSrcNativeVariant)
+ {
+ var pv = new PROPVARIANT();
+ VariantToPropVariant(pSrcNativeVariant, pv).ThrowIfFailed();
+ return pv;
+ }
+
/// Gets the Type for a provided VARTYPE.
/// The VARTYPE value to lookup.
/// A best fit for the provided VARTYPE.
@@ -571,9 +509,10 @@ namespace Vanara.PInvoke
if (type.IsArray && elemtype == typeof(object)) return VARTYPE.VT_ARRAY | VARTYPE.VT_VARIANT;
var isEnumerable = type.IsArray || type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type);
- var ret = isEnumerable ? VARTYPE.VT_VECTOR : 0;
- if (isEnumerable && type.IsGenericType)
+ VARTYPE ret = 0;
+ if (isEnumerable)
{
+ ret |= VARTYPE.VT_VECTOR;
var i = type.GetInterface("IEnumerable`1");
if (i != null)
{
@@ -663,13 +602,57 @@ namespace Vanara.PInvoke
}
///
- /// Frees all elements that can be freed in this instance. For complex elements with known element pointers, the underlying elements are freed prior
- /// to freeing the containing element.
+ /// Frees all elements that can be freed in this instance. For complex elements with known element pointers, the underlying
+ /// elements are freed prior to freeing the containing element.
///
[SecurityCritical, SecuritySafeCritical]
public void Clear()
{
- PropVariantClear(this);
+ switch (vt)
+ {
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_BSTR:
+ foreach (var ptr in _blob.pBlobData.ToIEnum((int)_blob.cbSize))
+ Marshal.FreeBSTR(Marshal.ReadIntPtr(ptr));
+ Marshal.FreeCoTaskMem(_blob.pBlobData);
+ break;
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_LPSTR:
+ foreach (var ptr in _blob.pBlobData.ToIEnum((int)_blob.cbSize))
+ Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(ptr));
+ Marshal.FreeCoTaskMem(_blob.pBlobData);
+ break;
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_I1:
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_R4:
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_CLSID:
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_DECIMAL:
+ case VARTYPE.VT_CF:
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_CF:
+ Marshal.FreeCoTaskMem(_ptr);
+ break;
+ case VARTYPE.VT_UNKNOWN:
+ case VARTYPE.VT_DISPATCH:
+ case VARTYPE.VT_STREAM:
+ case VARTYPE.VT_STREAMED_OBJECT:
+ case VARTYPE.VT_STORAGE:
+ case VARTYPE.VT_STORED_OBJECT:
+ Marshal.Release(_ptr);
+ break;
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_UNKNOWN:
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_DISPATCH:
+ foreach (var iunk in GetVector())
+ Marshal.Release(iunk);
+ Marshal.FreeCoTaskMem(_ptr);
+ break;
+ case VARTYPE.VT_VECTOR | VARTYPE.VT_VARIANT:
+ foreach (var pv in GetVector())
+ pv.Dispose();
+ Marshal.FreeCoTaskMem(_ptr);
+ break;
+ default:
+ PropVariantClear(this);
+ break;
+ }
+ vt = 0;
+ _ulong = 0;
}
/// Copies the contents of one PROPVARIANT structure to another.
@@ -680,417 +663,50 @@ namespace Vanara.PInvoke
PropVariantCopy(clone, this);
}
- /// Creates a new object that is a copy of the current instance.
- /// A new object that is a copy of this instance.
- object ICloneable.Clone()
- {
- Clone(out PROPVARIANT pv);
- return pv;
- }
-
///
- /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes,
- /// follows, or occurs in the same position in the sort order as the other object.
+ /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current
+ /// instance precedes, follows, or occurs in the same position in the sort order as the other object.
///
/// An object to compare with this instance.
///
- /// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This
- /// instance precedes in the sort order. Zero This instance occurs in the same position in the sort order as . Greater than zero This instance follows in the sort order.
+ /// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning
+ /// Less than zero This instance precedes in the sort order. Zero This instance occurs in the same
+ /// position in the sort order as . Greater than zero This instance follows in
+ /// the sort order.
///
public int CompareTo(object other)
{
var v = Value;
- if (other == null) return v == null ? 0 : 1;
+ if (other is null) return v == null ? 0 : 1;
if (other is PROPVARIANT pv) return PropVariantCompare(this, pv);
- if (v == null) return -1;
+ if (v is null) return -1;
var pvDest = new PROPVARIANT();
if (PropVariantChangeType(pvDest, this, PROPVAR_CHANGE_FLAGS.PVCHF_DEFAULT, GetVarType(other.GetType())).Succeeded)
return PropVariantCompare(this, pvDest);
throw new ArgumentException(@"Unable to compare supplied object to PROPVARIANT.", nameof(other));
}
- /// Compares the current object with another object of the same type.
- /// An object to compare with this object.
- ///
- /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: Value
- /// Meaning Less than zero This object is less than the parameter.Zero This object is equal to .
- /// Greater than zero This object is greater than .
- ///
- int IComparable.CompareTo(PROPVARIANT other) => CompareTo(other);
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ public void Dispose()
+ {
+ Clear();
+ GC.SuppressFinalize(this);
+ }
/// Determines whether the specified , is equal to this instance.
/// The to compare with this instance.
/// true if the specified is equal to this instance; otherwise, false.
- public override bool Equals(object obj)
- {
- var pv = obj as PROPVARIANT;
- return pv != null ? Equals(pv.Value) : obj == this;
- }
+ public override bool Equals(object obj) => obj is PROPVARIANT pv ? Equals(pv.Value) : obj == this;
/// Indicates whether the current object is equal to another object of the same type.
/// An object to compare with this object.
/// true if the current object is equal to the parameter; otherwise, false.
public bool Equals(PROPVARIANT other) => CompareTo(other) == 0;
- /// Creates a new instance from a pointer to a VARIANT.
- /// A pointer to a native in-memory VARIANT.
- /// A new instance converted from the VARIANT pointer.
- public static PROPVARIANT FromNativeVariant(IntPtr pSrcNativeVariant)
- {
- var pv = new PROPVARIANT();
- VariantToPropVariant(pSrcNativeVariant, pv).ThrowIfFailed();
- return pv;
- }
-
/// Returns a hash code for this instance.
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
public override int GetHashCode() => vt.GetHashCode();
- /// Sets the value, clearing any existing value.
- /// The value.
- /// If this value equals VT_EMPTY, the method will attempt to ascertain the value type from the .
- private void SetValue(object value, VarEnum vEnum = VarEnum.VT_EMPTY)
- {
- Clear();
- vt = vEnum == VarEnum.VT_EMPTY ? GetVarType(value?.GetType()) : (VARTYPE)vEnum;
-
- // Finished if NULL or EMPTY
- if ((int)vt <= 1) return;
-
- // Handle SAFEARRAY
- if (vt.IsFlagSet(VARTYPE.VT_ARRAY))
- {
- SetSafeArray((object[])value);
- return;
- }
-
- // Handle BYREF null value
- if (vt.IsFlagSet(VARTYPE.VT_BYREF) && value == null)
- return;
-
- // Handle case where element type is put in w/o specifying VECTOR
- if (value != null && !vt.IsFlagSet(VARTYPE.VT_VECTOR) && value.GetType().IsArray) vt |= VARTYPE.VT_VECTOR;
-
- switch (vt)
- {
- case VARTYPE.VT_I1:
- case VARTYPE.VT_BYREF | VARTYPE.VT_I1:
- SetStruct((sbyte?)value, VarType);
- break;
-
- case VARTYPE.VT_UI1:
- case VARTYPE.VT_BYREF | VARTYPE.VT_UI1:
- SetStruct((byte?)value, VarType);
- break;
-
- case VARTYPE.VT_I2:
- case VARTYPE.VT_BYREF | VARTYPE.VT_I2:
- SetStruct((short?)value, VarType);
- break;
-
- case VARTYPE.VT_UI2:
- case VARTYPE.VT_BYREF | VARTYPE.VT_UI2:
- SetStruct((ushort?)value, VarType);
- break;
-
- case VARTYPE.VT_I4:
- case VARTYPE.VT_INT:
- case VARTYPE.VT_BYREF | VARTYPE.VT_I4:
- case VARTYPE.VT_BYREF | VARTYPE.VT_INT:
- SetStruct((int?)value, VarType);
- break;
-
- case VARTYPE.VT_UI4:
- case VARTYPE.VT_UINT:
- case VARTYPE.VT_BYREF | VARTYPE.VT_UI4:
- case VARTYPE.VT_BYREF | VARTYPE.VT_UINT:
- SetStruct((uint?)value, VarType);
- break;
-
- case VARTYPE.VT_I8:
- case VARTYPE.VT_BYREF | VARTYPE.VT_I8:
- SetStruct((long?)value, VarType);
- break;
-
- case VARTYPE.VT_UI8:
- case VARTYPE.VT_BYREF | VARTYPE.VT_UI8:
- SetStruct((ulong?)value, VarType);
- break;
-
- case VARTYPE.VT_R4:
- case VARTYPE.VT_BYREF | VARTYPE.VT_R4:
- SetStruct((float?)value, VarType);
- break;
-
- case VARTYPE.VT_R8:
- case VARTYPE.VT_BYREF | VARTYPE.VT_R8:
- SetStruct((double?)value, VarType);
- break;
-
- case VARTYPE.VT_BOOL:
- case VARTYPE.VT_BYREF | VARTYPE.VT_BOOL:
- SetStruct((bool?)value, VarType);
- break;
-
- case VARTYPE.VT_ERROR:
- case VARTYPE.VT_BYREF | VARTYPE.VT_ERROR:
- {
- uint? i;
- if (value is Win32Error)
- i = (uint?)(int)(Win32Error)value;
- else
- i = (uint)Convert.ChangeType(value, typeof(uint));
- SetStruct(i, VarType);
- }
- break;
-
- case VARTYPE.VT_HRESULT:
- case VARTYPE.VT_BYREF | VARTYPE.VT_HRESULT:
- {
- uint? i;
- if (value is HRESULT)
- i = (uint?)(int)(HRESULT)value;
- else
- i = (uint)Convert.ChangeType(value, typeof(uint));
- SetStruct(i, VarType);
- }
- break;
-
- case VARTYPE.VT_CY:
- case VARTYPE.VT_BYREF | VARTYPE.VT_CY:
- {
- ulong? i;
- if (value is decimal)
- i = (ulong?)decimal.ToOACurrency((decimal)value);
- else
- i = (ulong)Convert.ChangeType(value, typeof(ulong));
- SetStruct(i, VarType);
- }
- break;
-
- case VARTYPE.VT_DATE:
- case VARTYPE.VT_BYREF | VARTYPE.VT_DATE:
- {
- double? d = null;
- var dt = value as DateTime?;
- if (dt != null)
- d = dt.Value.ToOADate();
- var ft = value as FILETIME?;
- if (ft != null)
- d = ft.Value.ToDateTime().ToOADate();
- if (d == null)
- d = (double)Convert.ChangeType(value, typeof(double));
- SetStruct(d, VarType);
- }
- break;
-
- case VARTYPE.VT_FILETIME:
- {
- FILETIME? ft;
- var dt = value as DateTime?;
- if (dt != null)
- ft = dt.Value.ToFileTimeStruct();
- else
- ft = value as FILETIME? ?? FileTimeExtensions.MakeFILETIME((ulong)Convert.ChangeType(value, typeof(ulong)));
- _ft = ft.GetValueOrDefault();
- }
- break;
-
- case VARTYPE.VT_CLSID:
- SetStruct((Guid?)value, VarType);
- break;
-
- case VARTYPE.VT_CF:
- //SetStruct((CLIPDATA?)value, VarType);
- //break;
- throw new NotSupportedException();
-
- case VARTYPE.VT_BLOB:
- case VARTYPE.VT_BLOB_OBJECT:
- _blob = (BLOB)value;
- break;
-
- case VARTYPE.VT_BSTR:
- case VARTYPE.VT_BYREF | VARTYPE.VT_BSTR:
- if (value is IntPtr)
- SetStruct((IntPtr?)value, VarType);
- else
- SetString(value?.ToString(), VarType);
- break;
-
- case VARTYPE.VT_LPSTR:
- case VARTYPE.VT_LPWSTR:
- SetString(value?.ToString(), VarType);
- break;
-
- case VARTYPE.VT_UNKNOWN:
- {
- var p = value as IntPtr? ?? Marshal.GetIUnknownForObject(value);
- SetStruct(p, VarType);
- }
- break;
-
-#if !(NETSTANDARD2_0)
- case VARTYPE.VT_DISPATCH:
- {
- var p = value as IntPtr? ?? Marshal.GetIDispatchForObject(value);
- SetStruct(p, VarType);
- }
- break;
-#endif
-
- case VARTYPE.VT_STREAM:
- case VARTYPE.VT_STREAMED_OBJECT:
- SetStruct(Marshal.GetComInterfaceForObject(value, typeof(IStream)), VarType);
- break;
-
- case VARTYPE.VT_STORAGE:
- case VARTYPE.VT_STORED_OBJECT:
- SetStruct(Marshal.GetComInterfaceForObject(value, typeof(IStorage)), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_I1:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_UI1:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_I2:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_UI2:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_I4:
- case VARTYPE.VT_VECTOR | VARTYPE.VT_INT:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_UI4:
- case VARTYPE.VT_VECTOR | VARTYPE.VT_UINT:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_I8:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_UI8:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_R4:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_R8:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_BOOL:
- SetVector(ConvertToEnum(value).Select(b => (ushort)(b ? -1 : 0)), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_ERROR:
- {
- var ee = (value as IEnumerable)?.Select(w => (uint)(int)w) ?? ConvertToEnum(value);
- SetVector(ee, VarType);
- }
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_HRESULT:
- {
- var ee = (value as IEnumerable)?.Select(w => (uint)(int)w) ?? ConvertToEnum(value);
- SetVector(ee, VarType);
- }
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_CY:
- {
- var ecy = (value as IEnumerable)?.Select(d => (ulong)decimal.ToOACurrency(d)) ??
- ConvertToEnum(value);
- SetVector(ecy, VarType);
- }
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_DATE:
- {
- var ed = (value as IEnumerable)?.Select(d => d.ToOADate()) ??
- (value as IEnumerable)?.Select(ft => ft.ToDateTime().ToOADate()) ??
- ConvertToEnum(value);
- SetVector(ed, VarType);
- }
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_FILETIME:
- {
- var ed = value as IEnumerable ??
- (value as IEnumerable)?.Select(d => d.ToFileTimeStruct()) ??
- ConvertToEnum(value)?.Select(FileTimeExtensions.MakeFILETIME);
- SetVector(ed, VarType);
- }
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_CLSID:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_CF:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_BSTR:
- {
- if (value is IEnumerable ep)
- SetVector(ep, VarType);
- else
- SetStringVector(ConvertToEnum(value), VarType);
- }
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_LPSTR:
- throw new NotSupportedException();
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_LPWSTR:
- SetStringVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_VARIANT:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_VECTOR | VARTYPE.VT_DECIMAL:
- SetVector(ConvertToEnum(value), VarType);
- break;
-
- case VARTYPE.VT_BYREF | VARTYPE.VT_DECIMAL:
- SetDecimal((decimal?)value);
- break;
-
- case VARTYPE.VT_BYREF | VARTYPE.VT_VARIANT:
- // TODO: Fix this so that it uses the system call in hopes that PropVarClear will actually release the memory.
- _ptr = this.StructureToPtr(Marshal.AllocCoTaskMem, out int _);
- break;
-
- case VARTYPE.VT_VOID:
- case VARTYPE.VT_PTR:
- case VARTYPE.VT_USERDEFINED:
- case VARTYPE.VT_RECORD:
- case VARTYPE.VT_BYREF | VARTYPE.VT_UNKNOWN:
- case VARTYPE.VT_BYREF | VARTYPE.VT_DISPATCH:
- _ptr = (IntPtr)value;
- break;
-
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
-
/// Returns a that represents this instance.
/// A that represents this instance.
public override string ToString()
@@ -1103,17 +719,35 @@ namespace Vanara.PInvoke
return $"{vt}={s ?? "null"}";
}
+ /// Creates a new object that is a copy of the current instance.
+ /// A new object that is a copy of this instance.
+ object ICloneable.Clone()
+ {
+ Clone(out var pv);
+ return pv;
+ }
+
+ /// Compares the current object with another object of the same type.
+ /// An object to compare with this object.
+ ///
+ /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following
+ /// meanings: Value Meaning Less than zero This object is less than the parameter.Zero This object is
+ /// equal to . Greater than zero This object is greater than .
+ ///
+ int IComparable.CompareTo(PROPVARIANT other) => CompareTo(other);
+
private static IEnumerable ConvertToEnum(object array, Func