[API Proposal]: Marshal overloads for ComVariant
- 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
Assessment
This issue has not been assessed yet.