Nullable: System.Runtime.InteropServices.CustomMarshalers/WindowsRuntime (#23930)
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / src / System / Runtime / InteropServices / CustomMarshalers / EnumerableViewOfDispatch.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #nullable enable
6 using System.Collections;
7 using System.Runtime.InteropServices.ComTypes;
8
9 namespace System.Runtime.InteropServices.CustomMarshalers
10 {
11     internal class EnumerableViewOfDispatch : ICustomAdapter, System.Collections.IEnumerable
12     {
13         // Reserved DISPID slot for getting an enumerator from an IDispatch-implementing COM interface.
14         private const int DISPID_NEWENUM = -4;
15         private const int LCID_DEFAULT = 1;
16         private readonly object _dispatch;
17
18         public EnumerableViewOfDispatch(object dispatch)
19         {
20             _dispatch = dispatch;
21         }
22
23         private IDispatch Dispatch => (IDispatch)_dispatch;
24
25         public IEnumerator GetEnumerator()
26         {
27             Variant result;
28             unsafe
29             {
30                 void *resultLocal = &result;
31                 DISPPARAMS dispParams = new DISPPARAMS();
32                 Guid guid = Guid.Empty;
33                 Dispatch.Invoke(
34                     DISPID_NEWENUM,
35                     ref guid,
36                     LCID_DEFAULT,
37                     InvokeFlags.DISPATCH_METHOD | InvokeFlags.DISPATCH_PROPERTYGET,
38                     ref dispParams,
39                     new IntPtr(resultLocal),
40                     IntPtr.Zero,
41                     IntPtr.Zero);
42             }
43
44             object? resultAsObject = result.ToObject();
45             if (!(resultAsObject is IEnumVARIANT enumVariant))
46             {
47                 throw new InvalidOperationException(SR.InvalidOp_InvalidNewEnumVariant);
48             }
49
50             return (IEnumerator)EnumeratorToEnumVariantMarshaler.GetInstance(null).MarshalNativeToManaged(Marshal.GetIUnknownForObject(enumVariant));
51         }
52
53         public object GetUnderlyingObject()
54         {
55             return _dispatch;
56         }
57     }
58 }