Skip to content

Commit 017b8aa

Browse files
committed
Refactor the Variants namespace, allowing classes to share the exported functions for DRY's sake. Also introduce VariantComparer class to implement the comparing of 2 variants.
1 parent 8695c05 commit 017b8aa

File tree

3 files changed

+148
-75
lines changed

3 files changed

+148
-75
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Globalization;
2+
3+
namespace Rubberduck.VBEditor.Variants
4+
{
5+
public static class VariantComparer
6+
{
7+
public static VariantComparisonResults Compare(object x, object y)
8+
{
9+
return Compare(x, y, VariantComparisonFlags.NORM_IGNORECASE);
10+
}
11+
12+
public static VariantComparisonResults Compare(object x, object y, VariantComparisonFlags flags)
13+
{
14+
return Compare(x, y, CultureInfo.InvariantCulture.LCID, flags);
15+
}
16+
17+
public static VariantComparisonResults Compare(object x, object y, int lcid, VariantComparisonFlags flags)
18+
{
19+
object dy;
20+
try
21+
{
22+
dy = VariantConverter.ChangeType(y, x.GetType());
23+
}
24+
catch
25+
{
26+
dy = y;
27+
}
28+
return (VariantComparisonResults)VariantNativeMethods.VarCmp(ref x, ref dy, lcid, (uint)flags);
29+
}
30+
}
31+
}

Rubberduck.VBEEditor/Variants/VariantConverter.cs

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,56 +4,6 @@
44

55
namespace Rubberduck.VBEditor.Variants
66
{
7-
public enum VARENUM
8-
{
9-
VT_EMPTY = 0x0000,
10-
VT_NULL = 0x0001,
11-
VT_I2 = 0x0002,
12-
VT_I4 = 0x0003,
13-
VT_R4 = 0x0004,
14-
VT_R8 = 0x0005,
15-
VT_CY = 0x0006,
16-
VT_DATE = 0x0007,
17-
VT_BSTR = 0x0008,
18-
VT_DISPATCH = 0x0009,
19-
VT_ERROR = 0x000A,
20-
VT_BOOL = 0x000B,
21-
VT_VARIANT = 0x000C,
22-
VT_UNKNOWN = 0x000D,
23-
VT_DECIMAL = 0x000E,
24-
VT_I1 = 0x0010,
25-
VT_UI1 = 0x0011,
26-
VT_UI2 = 0x0012,
27-
VT_UI4 = 0x0013,
28-
VT_I8 = 0x0014,
29-
VT_UI8 = 0x0015,
30-
VT_INT = 0x0016,
31-
VT_UINT = 0x0017,
32-
VT_VOID = 0x0018,
33-
VT_HRESULT = 0x0019,
34-
VT_PTR = 0x001A,
35-
VT_SAFEARRAY = 0x001B,
36-
VT_CARRAY = 0x001C,
37-
VT_USERDEFINED = 0x001D,
38-
VT_LPSTR = 0x001E,
39-
VT_LPWSTR = 0x001F,
40-
VT_RECORD = 0x0024,
41-
VT_INT_PTR = 0x0025,
42-
VT_UINT_PTR = 0x0026,
43-
VT_ARRAY = 0x2000,
44-
VT_BYREF = 0x4000
45-
}
46-
47-
[Flags]
48-
public enum VariantConversionFlags : ushort
49-
{
50-
NO_FLAGS = 0x00,
51-
VARIANT_NOVALUEPROP = 0x01, //Prevents the function from attempting to coerce an object to a fundamental type by getting the Value property. Applications should set this flag only if necessary, because it makes their behavior inconsistent with other applications.
52-
VARIANT_ALPHABOOL = 0x02, //Converts a VT_BOOL value to a string containing either "True" or "False".
53-
VARIANT_NOUSEROVERRIDE = 0x04, //For conversions to or from VT_BSTR, passes LOCALE_NOUSEROVERRIDE to the core coercion routines.
54-
VARIANT_LOCALBOOL = 0x08 //For conversions from VT_BOOL to VT_BSTR and back, uses the language specified by the locale in use on the local computer.
55-
}
56-
577
/// <summary>
588
/// Handles variant conversions, enabling us to have same implicit conversion behaviors within
599
/// .NET as we can observe it from VBA/VB6.
@@ -67,40 +17,18 @@ public enum VariantConversionFlags : ushort
6717
/// </remarks>
6818
public static class VariantConverter
6919
{
70-
private const string dllName = "oleaut32.dll";
71-
72-
// HRESULT VariantChangeType(
73-
// VARIANTARG *pvargDest,
74-
// const VARIANTARG *pvarSrc,
75-
// USHORT wFlags,
76-
// VARTYPE vt
77-
// );
78-
[DllImport(dllName, EntryPoint = "VariantChangeType", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
79-
private static extern int VariantChangeType(ref object pvargDest, ref object pvarSrc, VariantConversionFlags wFlags, VARENUM vt);
80-
81-
// HRESULT VariantChangeTypeEx(
82-
// VARIANTARG *pvargDest,
83-
// const VARIANTARG *pvarSrc,
84-
// LCID lcid,
85-
// USHORT wFlags,
86-
// VARTYPE vt
87-
// );
88-
[DllImport(dllName, EntryPoint = "VariantChangeTypeEx", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
89-
private static extern int VariantChangeTypeEx(ref object pvargDest, ref object pvarSrc, int lcid, VariantConversionFlags wFlags, VARENUM vt);
90-
9120
public static object ChangeType(object value, VARENUM vt)
9221
{
9322
return ChangeType(value, vt, null);
9423
}
9524

96-
private static bool HRESULT_FAILED(int hr) => hr < 0;
9725
public static object ChangeType(object value, VARENUM vt, CultureInfo cultureInfo)
9826
{
9927
object result = null;
10028
var hr = cultureInfo == null
101-
? VariantChangeType(ref result, ref value, VariantConversionFlags.NO_FLAGS, vt)
102-
: VariantChangeTypeEx(ref result, ref value, cultureInfo.LCID, VariantConversionFlags.NO_FLAGS, vt);
103-
if (HRESULT_FAILED(hr))
29+
? VariantNativeMethods.VariantChangeType(ref result, ref value, VariantConversionFlags.NO_FLAGS, vt)
30+
: VariantNativeMethods.VariantChangeTypeEx(ref result, ref value, cultureInfo.LCID, VariantConversionFlags.NO_FLAGS, vt);
31+
if (HResult.Failed(hr))
10432
{
10533
throw Marshal.GetExceptionForHR(hr);
10634
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace Rubberduck.VBEditor.Variants
5+
{
6+
public enum VARENUM
7+
{
8+
VT_EMPTY = 0x0000,
9+
VT_NULL = 0x0001,
10+
VT_I2 = 0x0002,
11+
VT_I4 = 0x0003,
12+
VT_R4 = 0x0004,
13+
VT_R8 = 0x0005,
14+
VT_CY = 0x0006,
15+
VT_DATE = 0x0007,
16+
VT_BSTR = 0x0008,
17+
VT_DISPATCH = 0x0009,
18+
VT_ERROR = 0x000A,
19+
VT_BOOL = 0x000B,
20+
VT_VARIANT = 0x000C,
21+
VT_UNKNOWN = 0x000D,
22+
VT_DECIMAL = 0x000E,
23+
VT_I1 = 0x0010,
24+
VT_UI1 = 0x0011,
25+
VT_UI2 = 0x0012,
26+
VT_UI4 = 0x0013,
27+
VT_I8 = 0x0014,
28+
VT_UI8 = 0x0015,
29+
VT_INT = 0x0016,
30+
VT_UINT = 0x0017,
31+
VT_VOID = 0x0018,
32+
VT_HRESULT = 0x0019,
33+
VT_PTR = 0x001A,
34+
VT_SAFEARRAY = 0x001B,
35+
VT_CARRAY = 0x001C,
36+
VT_USERDEFINED = 0x001D,
37+
VT_LPSTR = 0x001E,
38+
VT_LPWSTR = 0x001F,
39+
VT_RECORD = 0x0024,
40+
VT_INT_PTR = 0x0025,
41+
VT_UINT_PTR = 0x0026,
42+
VT_ARRAY = 0x2000,
43+
VT_BYREF = 0x4000
44+
}
45+
46+
[Flags]
47+
public enum VariantConversionFlags : ushort
48+
{
49+
NO_FLAGS = 0x00,
50+
VARIANT_NOVALUEPROP = 0x01, //Prevents the function from attempting to coerce an object to a fundamental type by getting the Value property. Applications should set this flag only if necessary, because it makes their behavior inconsistent with other applications.
51+
VARIANT_ALPHABOOL = 0x02, //Converts a VT_BOOL value to a string containing either "True" or "False".
52+
VARIANT_NOUSEROVERRIDE = 0x04, //For conversions to or from VT_BSTR, passes LOCALE_NOUSEROVERRIDE to the core coercion routines.
53+
VARIANT_LOCALBOOL = 0x08 //For conversions from VT_BOOL to VT_BSTR and back, uses the language specified by the locale in use on the local computer.
54+
}
55+
56+
[Flags]
57+
public enum VariantComparisonFlags : ulong
58+
{
59+
NO_FLAGS = 0x00,
60+
NORM_IGNORECASE = 0x00000001, //Ignore case.
61+
NORM_IGNORENONSPACE = 0x00000002, //Ignore nonspace characters.
62+
NORM_IGNORESYMBOLS = 0x00000004, //Ignore symbols.
63+
NORM_IGNOREWIDTH = 0x00000008, //Ignore string width.
64+
NORM_IGNOREKANATYPE = 0x00000040, //Ignore Kana type.
65+
NORM_IGNOREKASHIDA = 0x00040000 //Ignore Arabic kashida characters.
66+
}
67+
68+
public enum VariantComparisonResults : int
69+
{
70+
VARCMP_LT = 0, //pvarLeft is less than pvarRight.
71+
VARCMP_EQ = 1, //The parameters are equal.
72+
VARCMP_GT = 2, //pvarLeft is greater than pvarRight.
73+
VARCMP_NULL = 3 //Either expression is NULL.
74+
}
75+
76+
public static class HResult
77+
{
78+
internal static bool Succeeded(int hr) => hr >= 0;
79+
internal static bool Failed(int hr) => hr < 0;
80+
}
81+
82+
internal static class VariantNativeMethods
83+
{
84+
private const string dllName = "oleaut32.dll";
85+
86+
// HRESULT VariantChangeType(
87+
// VARIANTARG *pvargDest,
88+
// const VARIANTARG *pvarSrc,
89+
// USHORT wFlags,
90+
// VARTYPE vt
91+
// );
92+
[DllImport(dllName, EntryPoint = "VariantChangeType", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
93+
internal static extern int VariantChangeType(ref object pvargDest, ref object pvarSrc, VariantConversionFlags wFlags, VARENUM vt);
94+
95+
// HRESULT VariantChangeTypeEx(
96+
// VARIANTARG *pvargDest,
97+
// const VARIANTARG *pvarSrc,
98+
// LCID lcid,
99+
// USHORT wFlags,
100+
// VARTYPE vt
101+
// );
102+
[DllImport(dllName, EntryPoint = "VariantChangeTypeEx", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
103+
internal static extern int VariantChangeTypeEx(ref object pvargDest, ref object pvarSrc, int lcid, VariantConversionFlags wFlags, VARENUM vt);
104+
105+
// HRESULT VarCmp(
106+
// LPVARIANT pvarLeft,
107+
// LPVARIANT pvarRight,
108+
// LCID lcid,
109+
// ULONG dwFlags
110+
// );
111+
[DllImport(dllName, EntryPoint = "VarCmp", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
112+
internal static extern int VarCmp(ref object pvarLeft, ref object pvarRight, int lcid, ulong dwFlags);
113+
}
114+
}

0 commit comments

Comments
 (0)