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