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 using System.Text;
6 using System.Security;
7 using System.Runtime.InteropServices;
8 
9 namespace System.DirectoryServices.Interop
10 {
11 #pragma warning disable BCL0015 // CoreFxPort
12     internal class SafeNativeMethods
13     {
14         [DllImport(ExternDll.Oleaut32, PreserveSig = false)]
VariantClear(IntPtr pObject)15         public static extern void VariantClear(IntPtr pObject);
16 
17         [DllImport(ExternDll.Oleaut32)]
VariantInit(IntPtr pObject)18         public static extern void VariantInit(IntPtr pObject);
19 
20         [DllImport(ExternDll.Activeds)]
FreeADsMem(IntPtr pVoid)21         public static extern bool FreeADsMem(IntPtr pVoid);
22 
23         public const int
24             FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200,
25             FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000,
26             FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000,
27             ERROR_MORE_DATA = 234,
28             ERROR_SUCCESS = 0;
29 
30         [DllImport(ExternDll.Activeds, CharSet = CharSet.Unicode)]
ADsGetLastError(out int error, StringBuilder errorBuffer, int errorBufferLength, StringBuilder nameBuffer, int nameBufferLength)31         public static extern int ADsGetLastError(out int error, StringBuilder errorBuffer,
32                                                  int errorBufferLength, StringBuilder nameBuffer, int nameBufferLength);
33 
34         [DllImport(ExternDll.Activeds, CharSet = CharSet.Unicode)]
ADsSetLastError(int error, string errorString, string provider)35         public static extern int ADsSetLastError(int error, string errorString, string provider);
36 
37         [DllImport(ExternDll.Kernel32, CharSet = CharSet.Unicode)]
FormatMessageW(int dwFlags, int lpSource, int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, int arguments)38         public static extern int FormatMessageW(int dwFlags, int lpSource, int dwMessageId,
39                                                 int dwLanguageId, StringBuilder lpBuffer, int nSize, int arguments);
40 
41         public class EnumVariant
42         {
43             private static readonly object s_noMoreValues = new object();
44             private object _currentValue = s_noMoreValues;
45             private IEnumVariant _enumerator;
46 
EnumVariant(IEnumVariant en)47             public EnumVariant(IEnumVariant en)
48             {
49                 _enumerator = en ?? throw new ArgumentNullException(nameof(en));
50             }
51 
52             /// <devdoc>
53             /// Moves the enumerator to the next value In the list.
54             /// </devdoc>
GetNext()55             public bool GetNext()
56             {
57                 Advance();
58                 return _currentValue != s_noMoreValues;
59             }
60 
61             /// <devdoc>
62             /// Returns the current value of the enumerator. If GetNext() has never been called,
63             /// or if it has been called but it returned false, will throw an exception.
64             /// </devdoc>
GetValue()65             public object GetValue()
66             {
67                 if (_currentValue == s_noMoreValues)
68                 {
69                     throw new InvalidOperationException(SR.DSEnumerator);
70                 }
71 
72                 return _currentValue;
73             }
74 
75             /// <devdoc>
76             /// Returns the enumerator to the start of the sequence.
77             /// </devdoc>
Reset()78             public void Reset()
79             {
80                 _enumerator.Reset();
81                 _currentValue = s_noMoreValues;
82             }
83 
84             /// <devdoc>
85             /// Moves the pointer to the next value In the contained IEnumVariant, and
86             /// stores the current value In currentValue.
87             /// </devdoc>
Advance()88             private void Advance()
89             {
90                 _currentValue = s_noMoreValues;
91                 IntPtr addr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(Variant)));
92                 try
93                 {
94                     int[] numRead = new int[] { 0 };
95                     VariantInit(addr);
96                     _enumerator.Next(1, addr, numRead);
97 
98                     try
99                     {
100                         if (numRead[0] > 0)
101                         {
102 #pragma warning disable 612, 618
103                             _currentValue = Marshal.GetObjectForNativeVariant(addr);
104 #pragma warning restore 612, 618
105                         }
106                     }
107                     finally
108                     {
109                         VariantClear(addr);
110                     }
111                 }
112                 finally
113                 {
114                     Marshal.FreeCoTaskMem(addr);
115                 }
116             }
117         }
118 
119         [ComImport]
120         [Guid("00020404-0000-0000-C000-000000000046")]
121         [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
122         public interface IEnumVariant
123         {
Next([In, MarshalAs(UnmanagedType.U4)] int celt, [In, Out] IntPtr rgvar, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pceltFetched)124             void Next([In, MarshalAs(UnmanagedType.U4)] int celt,
125                       [In, Out] IntPtr rgvar,
126                       [Out, MarshalAs(UnmanagedType.LPArray)] int[] pceltFetched);
127 
Skip([In, MarshalAs(UnmanagedType.U4)] int celt)128             void Skip([In, MarshalAs(UnmanagedType.U4)] int celt);
129 
Reset()130             void Reset();
131 
Clone([Out, MarshalAs(UnmanagedType.LPArray)] IEnumVariant[] ppenum)132             void Clone([Out, MarshalAs(UnmanagedType.LPArray)] IEnumVariant[] ppenum);
133         }
134     }
135 }
136