Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
ComRuntimeHelpers.cs447 linesDownload Raw Back to ComInterop
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 4using System;5using System.Diagnostics;6using System.Linq;7using System.Reflection;8using System.Reflection.Emit;9using System.Management.Automation.InteropServices;10using System.Runtime.InteropServices;11using System.Security;12using ComTypes = System.Runtime.InteropServices.ComTypes;13 14namespace System.Management.Automation.ComInterop15{16    internal static class ComRuntimeHelpers17    {18        public static void CheckThrowException(int hresult, ref ExcepInfo excepInfo, ComMethodDesc method, object[] args, uint argErr)19        {20            if (ComHresults.IsSuccess(hresult))21            {22                return;23            }24            Exception parameterException = null;25 26            switch (hresult)27            {28                case ComHresults.DISP_E_BADPARAMCOUNT:29                    // The number of elements provided to DISPPARAMS is different from the number of arguments30                    // accepted by the method or property.31                    parameterException = Error.DispBadParamCount(method.Name, args.Length - 1);32                    ThrowWrappedInvocationException(method, parameterException);33                    break;34 35                case ComHresults.DISP_E_BADVARTYPE:36                    //One of the arguments in rgvarg is not a valid variant type.37                    break;38 39                case ComHresults.DISP_E_EXCEPTION:40                    // The application needs to raise an exception. In this case, the structure passed in pExcepInfo41                    // should be filled in.42                    throw excepInfo.GetException();43 44                case ComHresults.DISP_E_MEMBERNOTFOUND:45                    // The requested member does not exist, or the call to Invoke tried to set the value of a46                    // read-only property.47                    throw Error.DispMemberNotFound(method.Name);48 49                case ComHresults.DISP_E_NONAMEDARGS:50                    // This implementation of IDispatch does not support named arguments.51                    throw Error.DispNoNamedArgs(method.Name);52 53                case ComHresults.DISP_E_OVERFLOW:54                    // One of the arguments in rgvarg could not be coerced to the specified type.55                    throw Error.DispOverflow(method.Name);56 57                case ComHresults.DISP_E_PARAMNOTFOUND:58                    // One of the parameter DISPIDs does not correspond to a parameter on the method. In this case,59                    // puArgErr should be set to the first argument that contains the error.60                    break;61 62                case ComHresults.DISP_E_TYPEMISMATCH:63                    // The index within rgvarg of the first parameter with the incorrect64                    // type is returned in the puArgErr parameter.65                    //66                    // But: Arguments are stored in pDispParams->rgvarg in reverse order, so the first67                    // parameter is the one with the highest index in the array68                    // https://msdn.microsoft.com/library/aa912367.aspx69                    argErr = ((uint)args.Length) - argErr - 2;70 71                    // One or more of the arguments could not be coerced.72 73                    Type destinationType = null;74                    if (argErr >= method.ParameterInformation.Length)75                    {76                        destinationType = method.InputType;77                    }78                    else79                    {80                        destinationType = method.ParameterInformation[argErr].parameterType;81                    }82 83                    object originalValue = args[argErr + 1];84 85                    // If this is a put, use the InputType and the last argument86                    if (method.IsPropertyPut || method.IsPropertyPutRef)87                    {88                        destinationType = method.InputType;89                        originalValue = args[args.Length - 1];90                    }91 92                    string originalValueString = originalValue.ToString();93                    string originalTypeName = Microsoft.PowerShell.ToStringCodeMethods.Type(originalValue.GetType(), true);94 95                    // ByRef arguments should be displayed in the error message as a PSReference96                    if (destinationType == typeof(object) && method.ParameterInformation[argErr].isByRef)97                    {98                        destinationType = typeof(PSReference);99                    }100 101                    string destinationTypeName = Microsoft.PowerShell.ToStringCodeMethods.Type(destinationType, true);102 103                    parameterException = Error.DispTypeMismatch(method.Name, originalValueString, originalTypeName, destinationTypeName);104                    ThrowWrappedInvocationException(method, parameterException);105                    break;106 107                case ComHresults.DISP_E_UNKNOWNINTERFACE:108                    // The interface identifier passed in riid is not IID_NULL.109                    break;110 111                case ComHresults.DISP_E_UNKNOWNLCID:112                    // The member being invoked interprets string arguments according to the LCID, and the113                    // LCID is not recognized.114                    break;115 116                case ComHresults.DISP_E_PARAMNOTOPTIONAL:117                    // A required parameter was omitted.118                    throw Error.DispParamNotOptional(method.Name);119            }120 121            Marshal.ThrowExceptionForHR(hresult);122        }123 124        private static void ThrowWrappedInvocationException(ComMethodDesc method, Exception parameterException)125        {126            if ((method.InvokeKind & ComTypes.INVOKEKIND.INVOKE_FUNC) ==127                ComTypes.INVOKEKIND.INVOKE_FUNC)128            {129                throw new MethodException(parameterException.Message, parameterException);130            }131 132            if (method.IsPropertyGet)133            {134                throw new GetValueInvocationException(parameterException.Message, parameterException);135            }136 137            if (method.IsPropertyPut || method.IsPropertyPutRef)138            {139                throw new SetValueInvocationException(parameterException.Message, parameterException);140            }141 142            throw parameterException;143        }144 145        internal static void GetInfoFromType(ComTypes.ITypeInfo typeInfo, out string name, out string documentation)146        {147            typeInfo.GetDocumentation(-1, out name, out documentation, out int _, out string _);148        }149 150        internal static string GetNameOfMethod(ComTypes.ITypeInfo typeInfo, int memid)151        {152            string[] rgNames = new string[1];153            typeInfo.GetNames(memid, rgNames, 1, out int _);154            return rgNames[0];155        }156 157        internal static string GetNameOfLib(ComTypes.ITypeLib typeLib)158        {159            typeLib.GetDocumentation(-1, out string name, out string _, out int _, out string _);160            return name;161        }162 163        internal static string GetNameOfType(ComTypes.ITypeInfo typeInfo)164        {165            GetInfoFromType(typeInfo, out string name, out string _);166 167            return name;168        }169 170        /// <summary>171        /// Look for typeinfo using IDispatch.GetTypeInfo.172        /// </summary>173        /// <param name="dispatch">IDispatch object</param>174        /// <remarks>175        /// Some COM objects just dont expose typeinfo. In these cases, this method will return null.176        /// Some COM objects do intend to expose typeinfo, but may not be able to do so if the type-library is not properly177        /// registered. This will be considered as acceptable or as an error condition depending on throwIfMissingExpectedTypeInfo178        /// </remarks>179        /// <returns>Type info</returns>180        internal static ComTypes.ITypeInfo GetITypeInfoFromIDispatch(IDispatch dispatch)181        {182            int hresult = dispatch.TryGetTypeInfoCount(out uint typeCount);183            if (hresult == ComHresults.E_NOTIMPL || hresult == ComHresults.E_NOINTERFACE)184            {185                // Allow the dynamic binding to continue using the original binder.186                return null;187            }188            else189            {190                Marshal.ThrowExceptionForHR(hresult);191            }192 193            Debug.Assert(typeCount <= 1);194            if (typeCount == 0)195            {196                return null;197            }198 199            IntPtr typeInfoPtr;200            hresult = dispatch.TryGetTypeInfo(0, 0, out typeInfoPtr);201            if (!ComHresults.IsSuccess(hresult))202            {203                // Word.Basic always returns this because of an incorrect implementation of IDispatch.GetTypeInfo204                // Any implementation that returns E_NOINTERFACE is likely to do so in all environments205                if (hresult == ComHresults.E_NOINTERFACE)206                {207                    return null;208                }209 210                // This assert is potentially over-restrictive since COM components can behave in quite unexpected ways.211                // However, asserting the common expected cases ensures that we find out about the unexpected scenarios, and212                // can investigate the scenarios to ensure that there is no bug in our own code.213                Debug.Assert(hresult == ComHresults.TYPE_E_LIBNOTREGISTERED);214 215                Marshal.ThrowExceptionForHR(hresult);216            }217 218            if (typeInfoPtr == IntPtr.Zero)219            {220                Marshal.ThrowExceptionForHR(ComHresults.E_FAIL);221            }222 223            ComTypes.ITypeInfo typeInfo = null;224            try225            {226                typeInfo = Marshal.GetObjectForIUnknown(typeInfoPtr) as ComTypes.ITypeInfo;227            }228            finally229            {230                Marshal.Release(typeInfoPtr);231            }232 233            return typeInfo;234        }235 236        internal static ComTypes.TYPEATTR GetTypeAttrForTypeInfo(ComTypes.ITypeInfo typeInfo)237        {238            IntPtr pAttrs;239            typeInfo.GetTypeAttr(out pAttrs);240 241            // GetTypeAttr should never return null, this is just to be safe242            if (pAttrs == IntPtr.Zero)243            {244                throw Error.CannotRetrieveTypeInformation();245            }246 247            try248            {249                return (ComTypes.TYPEATTR)Marshal.PtrToStructure(pAttrs, typeof(ComTypes.TYPEATTR));250            }251            finally252            {253                typeInfo.ReleaseTypeAttr(pAttrs);254            }255        }256 257        internal static ComTypes.TYPELIBATTR GetTypeAttrForTypeLib(ComTypes.ITypeLib typeLib)258        {259            IntPtr pAttrs;260            typeLib.GetLibAttr(out pAttrs);261 262            // GetTypeAttr should never return null, this is just to be safe263            if (pAttrs == IntPtr.Zero)264            {265                throw Error.CannotRetrieveTypeInformation();266            }267 268            try269            {270                return (ComTypes.TYPELIBATTR)Marshal.PtrToStructure(pAttrs, typeof(ComTypes.TYPELIBATTR));271            }272            finally273            {274                typeLib.ReleaseTLibAttr(pAttrs);275            }276        }277 278        public static BoundDispEvent CreateComEvent(object rcw, Guid sourceIid, int dispid)279        {280            return new BoundDispEvent(rcw, sourceIid, dispid);281        }282 283        public static DispCallable CreateDispCallable(IDispatchComObject dispatch, ComMethodDesc method)284        {285            return new DispCallable(dispatch, method.Name, method.DispId);286        }287    }288 289    /// <summary>290    /// This class contains methods that either cannot be expressed in C#, or which require writing unsafe code.291    /// Callers of these methods need to use them extremely carefully as incorrect use could cause GC-holes292    /// and other problems.293    /// </summary>294    ///295    internal static class UnsafeMethods296    {297        #region public members298 299        public static unsafe IntPtr ConvertInt32ByrefToPtr(ref int value)300        {301            return (IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref value);302        }303 304        public static unsafe IntPtr ConvertVariantByrefToPtr(ref Variant value)305        {306            return (IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref value);307        }308 309        internal static Variant GetVariantForObject(object obj)310        {311            Variant variant = default;312            if (obj == null)313            {314                return variant;315            }316            InitVariantForObject(obj, ref variant);317            return variant;318        }319 320        internal static void InitVariantForObject(object obj, ref Variant variant)321        {322            Debug.Assert(obj != null);323 324            // GetNativeVariantForObject is very expensive for values that marshal as VT_DISPATCH325            // also is extremely common scenario when object at hand is an RCW.326            // Therefore we are going to test for IDispatch before defaulting to GetNativeVariantForObject.327            if (obj is IDispatch)328            {329                variant.AsDispatch = obj;330                return;331            }332 333            Marshal.GetNativeVariantForObject(obj, ConvertVariantByrefToPtr(ref variant));334        }335 336        // This method is intended for use through reflection and should not be used directly337        public static object GetObjectForVariant(Variant variant)338        {339            IntPtr ptr = UnsafeMethods.ConvertVariantByrefToPtr(ref variant);340            return Marshal.GetObjectForNativeVariant(ptr);341        }342 343        // This method is intended for use through reflection and should only be used directly by IUnknownReleaseNotZero344        public static unsafe int IUnknownRelease(IntPtr interfacePointer)345        {346            return ((delegate* unmanaged<IntPtr, int>)(*(*(void***)interfacePointer + 2 /* IUnknown.Release slot */)))(interfacePointer);347        }348 349        // This method is intended for use through reflection and should not be used directly350        public static void IUnknownReleaseNotZero(IntPtr interfacePointer)351        {352            if (interfacePointer != IntPtr.Zero)353            {354                IUnknownRelease(interfacePointer);355            }356        }357 358        // This method is intended for use through reflection and should not be used directly359        public static unsafe int IDispatchInvoke(360            IntPtr dispatchPointer,361            int memberDispId,362            ComTypes.INVOKEKIND flags,363            ref ComTypes.DISPPARAMS dispParams,364            out Variant result,365            out ExcepInfo excepInfo,366            out uint argErr)367        {368            Guid IID_NULL = default;369 370            fixed (ComTypes.DISPPARAMS* pDispParams = &dispParams)371            fixed (Variant* pResult = &result)372            fixed (ExcepInfo* pExcepInfo = &excepInfo)373            fixed (uint* pArgErr = &argErr)374            {375                var pfnIDispatchInvoke = (delegate* unmanaged<IntPtr, int, Guid*, int, ushort, ComTypes.DISPPARAMS*, Variant*, ExcepInfo*, uint*, int>)(*(*(void***)dispatchPointer + 6 /* IDispatch.Invoke slot */));376 377                int hresult = pfnIDispatchInvoke(dispatchPointer,378                    memberDispId, &IID_NULL, 0, (ushort)flags, pDispParams, pResult, pExcepInfo, pArgErr);379 380                if (hresult == ComHresults.DISP_E_MEMBERNOTFOUND381                    && (flags & ComTypes.INVOKEKIND.INVOKE_FUNC) != 0382                    && (flags & (ComTypes.INVOKEKIND.INVOKE_PROPERTYPUT | ComTypes.INVOKEKIND.INVOKE_PROPERTYPUTREF)) == 0)383                {384                    // Re-invoke with no result argument to accommodate Word385                    hresult = pfnIDispatchInvoke(dispatchPointer,386                        memberDispId, &IID_NULL, 0, (ushort)ComTypes.INVOKEKIND.INVOKE_FUNC, pDispParams, null, pExcepInfo, pArgErr);387                }388 389                return hresult;390            }391        }392 393        // This method is intended for use through reflection and should not be used directly394        public static IntPtr GetIdsOfNamedParameters(IDispatch dispatch, string[] names, int methodDispId, out GCHandle pinningHandle)395        {396            pinningHandle = GCHandle.Alloc(null, GCHandleType.Pinned);397            int[] dispIds = new int[names.Length];398            Guid empty = Guid.Empty;399            int hresult = dispatch.TryGetIDsOfNames(ref empty, names, (uint)names.Length, 0, dispIds);400            if (hresult < 0)401            {402                Marshal.ThrowExceptionForHR(hresult);403            }404 405            if (methodDispId != dispIds[0])406            {407                throw Error.GetIDsOfNamesInvalid(names[0]);408            }409 410            int[] keywordArgDispIds = dispIds.RemoveFirst(); // Remove the dispId of the method name411 412            pinningHandle.Target = keywordArgDispIds;413            return Marshal.UnsafeAddrOfPinnedArrayElement(keywordArgDispIds, 0);414        }415 416        #endregion417 418        #region non-public members419 420        private static readonly object s_lock = new object();421        private static ModuleBuilder s_dynamicModule;422 423        internal static ModuleBuilder DynamicModule424        {425            get426            {427                if (s_dynamicModule != null)428                {429                    return s_dynamicModule;430                }431                lock (s_lock)432                {433                    if (s_dynamicModule == null)434                    {435                        string name = typeof(VariantArray).Namespace + ".DynamicAssembly";436                        var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.Run);437                        s_dynamicModule = assembly.DefineDynamicModule(name);438                    }439                    return s_dynamicModule;440                }441            }442        }443 444        #endregion445    }446}447