Skip to content

Conversation

@jkoritzinsky
Copy link
Member

OleDb and DirectoryServices were using their own representations of the Win32 VARIANT and PROPVARIANT types. Unify on the ComVariant type as it follows interop best practices to map the Win32 VARIANT type.

Copilot AI review requested due to automatic review settings January 10, 2026 01:50
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jan 10, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request replaces custom VARIANT and PROPVARIANT type definitions in System.DirectoryServices and System.Data.OleDb libraries with the standard ComVariant type from System.Runtime.InteropServices.Marshalling. This unification follows interop best practices for representing Win32 VARIANT types.

Key changes:

  • Removed custom Variant and PROPVARIANT struct definitions and replaced them with ComVariant
  • Consolidated VARIANT and PROPVARIANT handling in OleDb to use the same cleanup code path
  • Updated all usages to call ComVariant.Create() and ComVariant.Dispose() instead of manual struct initialization and native cleanup functions

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/libraries/System.DirectoryServices/src/System/DirectoryServices/DirectoryEntry.cs Replaced manual VARIANT initialization with ComVariant.Create(true)
src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj Removed references to VariantClear and VariantInit interop files
src/libraries/System.DirectoryServices/src/Interop/UnsafeNativeMethods.cs Removed custom Variant struct and updated IAdsObjectOptions2 to use ComVariant
src/libraries/System.DirectoryServices/src/Interop/EnumVariant.cs Updated to use ComVariant with proper disposal pattern
src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj Removed references to VariantClear and PropVariantClear interop files
src/libraries/System.Data.OleDb/src/SafeHandles.cs Removed entire PROPVARIANT struct definition and related types (307 lines)
src/libraries/System.Data.OleDb/src/RowBinding.cs Consolidated VARIANT and PROPVARIANT cleanup to use single code path with ComVariant
src/libraries/System.Data.OleDb/src/PropertyInfoSet.cs Updated to use ComVariant.Dispose() instead of VariantClear
src/libraries/System.Data.OleDb/src/OleDb_Util.cs Updated SizeOf_Variant calculation to use Unsafe.SizeOf()
src/libraries/System.Data.OleDb/src/OleDb_Enum.cs Updated D_PropVariant size to use sizeof(ComVariant)
src/libraries/System.Data.OleDb/src/DbPropSet.cs Updated to use ComVariant.Dispose() instead of VariantClear
src/libraries/System.Data.OleDb/src/DbBindings.cs Updated comments to reference ComVariant instead of PROPVARIANT
src/libraries/Common/src/Interop/Windows/OleAut32/Interop.VariantInit.cs Deleted file - no longer needed with ComVariant

@jkotas jkotas added area-System.Runtime.InteropServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jan 10, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

Comment on lines +148 to +149
ref ComVariant variant = ref *(ComVariant*)vptr;
variant.Dispose();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this better? Passing the IntPtr to a well-defined P/Invoke seems a lot clearer rather than casting to some interop type and calling Dispose().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially made this change with the intent to swap other usages of the PROPVARIANT type to the new API. I later realized that the only usages of it were for size calculations (and actually fetching the value into a .NET value was done with Marshal.GetObjectForNativeVariant. I'll revert the Dispose changes back to using PropVariantClear.

internal static readonly int SizeOf_tagDBPROPIDSET = Marshal.SizeOf<tagDBPROPIDSET>();
internal static readonly int SizeOf_Guid = Marshal.SizeOf<Guid>();
internal static readonly int SizeOf_Variant = 8 + (2 * IntPtr.Size); // 16 on 32bit, 24 on 64bit
internal static readonly int SizeOf_Variant = Unsafe.SizeOf<ComVariant>(); // 16 on 32bit, 24 on 64bit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
internal static readonly int SizeOf_Variant = Unsafe.SizeOf<ComVariant>(); // 16 on 32bit, 24 on 64bit
internal static readonly int SizeOf_Variant = Unsafe.SizeOf<ComVariant>();

{
IntPtr valuePtr = ADP.IntPtrOffset(infoPtr, (k * ODB.SizeOf_tagDBPROPINFO) + ODB.OffsetOf_tagDBPROPINFO_Value);
Interop.OleAut32.VariantClear(valuePtr);
ref ComVariant variant = ref *(ComVariant*)valuePtr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants