Example #1
0
        /// <summary>
        /// Look for typeinfo using IDispatch.GetTypeInfo.
        /// </summary>
        /// <param name="dispatch">IDispatch object</param>
        /// <remarks>
        /// Some COM objects just dont expose typeinfo. In these cases, this method will return null.
        /// Some COM objects do intend to expose typeinfo, but may not be able to do so if the type-library is not properly
        /// registered. This will be considered as acceptable or as an error condition depending on throwIfMissingExpectedTypeInfo
        /// </remarks>
        /// <returns>Type info</returns>
        internal static ComTypes.ITypeInfo GetITypeInfoFromIDispatch(IDispatch dispatch)
        {
            int hresult = dispatch.TryGetTypeInfoCount(out uint typeCount);

            if (hresult == ComHresults.E_NOTIMPL || hresult == ComHresults.E_NOINTERFACE)
            {
                // Allow the dynamic binding to continue using the original binder.
                return(null);
            }
            else
            {
                Marshal.ThrowExceptionForHR(hresult);
            }

            Debug.Assert(typeCount <= 1);
            if (typeCount == 0)
            {
                return(null);
            }

            IntPtr typeInfoPtr;

            hresult = dispatch.TryGetTypeInfo(0, 0, out typeInfoPtr);
            if (!ComHresults.IsSuccess(hresult))
            {
                // Word.Basic always returns this because of an incorrect implementation of IDispatch.GetTypeInfo
                // Any implementation that returns E_NOINTERFACE is likely to do so in all environments
                if (hresult == ComHresults.E_NOINTERFACE)
                {
                    return(null);
                }

                // This assert is potentially over-restrictive since COM components can behave in quite unexpected ways.
                // However, asserting the common expected cases ensures that we find out about the unexpected scenarios, and
                // can investigate the scenarios to ensure that there is no bug in our own code.
                Debug.Assert(hresult == ComHresults.TYPE_E_LIBNOTREGISTERED);

                Marshal.ThrowExceptionForHR(hresult);
            }

            if (typeInfoPtr == IntPtr.Zero)
            {
                Marshal.ThrowExceptionForHR(ComHresults.E_FAIL);
            }

            ComTypes.ITypeInfo typeInfo = null;
            try
            {
                typeInfo = Marshal.GetObjectForIUnknown(typeInfoPtr) as ComTypes.ITypeInfo;
            }
            finally
            {
                Marshal.Release(typeInfoPtr);
            }

            return(typeInfo);
        }
Example #2
0
        public static void CheckThrowException(int hresult, ref ExcepInfo excepInfo, ComMethodDesc method, object[] args, uint argErr)
        {
            if (ComHresults.IsSuccess(hresult))
            {
                return;
            }
            Exception parameterException = null;

            switch (hresult)
            {
            case ComHresults.DISP_E_BADPARAMCOUNT:
                // The number of elements provided to DISPPARAMS is different from the number of arguments
                // accepted by the method or property.
                parameterException = Error.DispBadParamCount(method.Name, args.Length - 1);
                ThrowWrappedInvocationException(method, parameterException);
                break;

            case ComHresults.DISP_E_BADVARTYPE:
                //One of the arguments in rgvarg is not a valid variant type.
                break;

            case ComHresults.DISP_E_EXCEPTION:
                // The application needs to raise an exception. In this case, the structure passed in pExcepInfo
                // should be filled in.
                throw excepInfo.GetException();

            case ComHresults.DISP_E_MEMBERNOTFOUND:
                // The requested member does not exist, or the call to Invoke tried to set the value of a
                // read-only property.
                throw Error.DispMemberNotFound(method.Name);

            case ComHresults.DISP_E_NONAMEDARGS:
                // This implementation of IDispatch does not support named arguments.
                throw Error.DispNoNamedArgs(method.Name);

            case ComHresults.DISP_E_OVERFLOW:
                // One of the arguments in rgvarg could not be coerced to the specified type.
                throw Error.DispOverflow(method.Name);

            case ComHresults.DISP_E_PARAMNOTFOUND:
                // One of the parameter DISPIDs does not correspond to a parameter on the method. In this case,
                // puArgErr should be set to the first argument that contains the error.
                break;

            case ComHresults.DISP_E_TYPEMISMATCH:
                // The index within rgvarg of the first parameter with the incorrect
                // type is returned in the puArgErr parameter.
                //
                // But: Arguments are stored in pDispParams->rgvarg in reverse order, so the first
                // parameter is the one with the highest index in the array
                // https://msdn.microsoft.com/library/aa912367.aspx
                argErr = ((uint)args.Length) - argErr - 2;

                // One or more of the arguments could not be coerced.

                Type destinationType = null;
                if (argErr >= method.ParameterInformation.Length)
                {
                    destinationType = method.InputType;
                }
                else
                {
                    destinationType = method.ParameterInformation[argErr].parameterType;
                }

                object originalValue = args[argErr + 1];

                // If this is a put, use the InputType and the last argument
                if (method.IsPropertyPut || method.IsPropertyPutRef)
                {
                    destinationType = method.InputType;
                    originalValue   = args[args.Length - 1];
                }

                string originalValueString = originalValue.ToString();
                string originalTypeName    = Microsoft.PowerShell.ToStringCodeMethods.Type(originalValue.GetType(), true);

                // ByRef arguments should be displayed in the error message as a PSReference
                if (destinationType == typeof(object) && method.ParameterInformation[argErr].isByRef)
                {
                    destinationType = typeof(PSReference);
                }

                string destinationTypeName = Microsoft.PowerShell.ToStringCodeMethods.Type(destinationType, true);

                parameterException = Error.DispTypeMismatch(method.Name, originalValueString, originalTypeName, destinationTypeName);
                ThrowWrappedInvocationException(method, parameterException);
                break;

            case ComHresults.DISP_E_UNKNOWNINTERFACE:
                // The interface identifier passed in riid is not IID_NULL.
                break;

            case ComHresults.DISP_E_UNKNOWNLCID:
                // The member being invoked interprets string arguments according to the LCID, and the
                // LCID is not recognized.
                break;

            case ComHresults.DISP_E_PARAMNOTOPTIONAL:
                // A required parameter was omitted.
                throw Error.DispParamNotOptional(method.Name);
            }

            Marshal.ThrowExceptionForHR(hresult);
        }