/// <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); }
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); }