dotnet / dotnet/runtime

[API Proposal]: Marshal overloads for ComVariant

Open
#123,096 8 comments 0 reactions 0 assignees View on GitHub
api-suggestion area-Interop-coreclr
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Background and motivation

In .NET Framework 1.0, we introduced methods on `Marshal` to handle converting between .NET `object` values and `IntPtr`s that point to native `VARIANT` values.

In .NET 9, we introduced the `System.Runtime.InteropServices.Marshalling.ComVariant` type as a standard representation of the Win32 `VARIANT` and `PROPVARIANT` types. This type has APIs on it to convert from the `VARIANT` value to a .NET representation, but it has a more limited set of supported conversions than the methods on Marshal (by design).

To support users who need to deal with `VARIANT`s manually and would like to use the `ComVariant` type to represent locals in .NET, I recommend we add the following APIs to `Marshal` to enable users to avoid using `IntPtr` overloads when not necessary.

For now, I am only proposing `GetObjectForNativeVariant` as that is the only method that has multiple use cases for this scenario in dotnet/runtime. `GetNativeVariantForObject` has one use case, and `GetObjectsForNativeVariants` has no use cases.

We don't have

### API Proposal

```csharp
namespace System.Runtime.InteropServices;

public static class Marshal
{
// Existing
public static void GetNativeVariantForObject(object? obj, IntPtr pDstNativeVariant);
public static void GetNativeVariantForObject(T? obj, IntPtr pDstNativeVariant);
public static object? GetObjectForNativeVariant(IntPtr pSrcNativeVariant);
public static T? GetObjectForNativeVariant(IntPtr pSrcNativeVariant);
public static object?[] GetObjectsForNativeVariants(IntPtr aSrcNativeVariant, int cVars);
public static T[] GetObjectsForNativeVariants(IntPtr aSrcNativeVariant, int cVars);

// New APIs
public static object? GetObjectForNativeVariant(in ComVariant variant);
public static T? GetObjectForNativeVariant(in ComVariant variant);
}
```

### API Usage

Slight variation on https://github.com/dotnet/runtime/blob/main/src/libraries/System.DirectoryServices/src/Interop/EnumVariant.cs

```csharp
_currentValue = s_noMoreValues;
ComVariant variant = default;
int[] numRead = new int[] { 0 };
_enumerator.Next(1, ref variant, numRead);

try
{
if (numRead[0] > 0)
{
_currentValue = Marshal.GetObjectForNativeVariant(variant)!;
}
}
finally
{
variant.Dispose();
}
```

### Alternative Designs

We could introduce overloads for the whole family of `object <-> VARIANT` conversion methods.

```csharp

public static void GetNativeVariantForObject(object? obj, out ComVariant variant);
public static void GetNativeVariantForObject(T? obj, out ComVariant variant);
public static ReadOnlySpan GetObjectsForNativeVariants(ReadOnlySpan variants);
public static ReadOnlySpan GetObjectsForNativeVariants(ReadOnlySpan variants);
```

### Risks

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.