/// <summary> /// Look for typeinfo using IDispatch.GetTypeInfo /// </summary> /// <param name="dispatch"></param> /// <param name="throwIfMissingExpectedTypeInfo"> /// 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</param> /// <returns></returns> internal static ComTypes.ITypeInfo GetITypeInfoFromIDispatch(IDispatch dispatch, bool throwIfMissingExpectedTypeInfo) { uint typeCount; int hresult = dispatch.TryGetTypeInfoCount(out typeCount); Marshal.ThrowExceptionForHR(hresult); Debug.Assert(typeCount <= 1); if (typeCount == 0) { return null; } IntPtr typeInfoPtr = IntPtr.Zero; hresult = dispatch.TryGetTypeInfo(0, 0, out typeInfoPtr); if (!ComHresults.IsSuccess(hresult)) { CheckIfMissingTypeInfoIsExpected(hresult, throwIfMissingExpectedTypeInfo); return null; } if (typeInfoPtr == IntPtr.Zero) { // be defensive against components that return IntPtr.Zero if (throwIfMissingExpectedTypeInfo) { Marshal.ThrowExceptionForHR(ComHresults.E_FAIL); } return null; } ComTypes.ITypeInfo typeInfo = null; try { typeInfo = Marshal.GetObjectForIUnknown(typeInfoPtr) as ComTypes.ITypeInfo; } finally { Marshal.Release(typeInfoPtr); } return typeInfo; }
/// <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); }
/// <summary> /// Look for type info using IDispatch.GetTypeInfo /// </summary> /// <param name="dispatch">IDispatch object</param> /// <remarks> /// Some COM objects just don't expose type info. In these cases, this method will return null. /// Some COM objects do intend to expose type info, but may not be able to do so if the type library /// is not properly registered. This will be considered an error. /// </remarks> /// <returns>Type info</returns> internal static ComTypes.ITypeInfo GetITypeInfoFromIDispatch(IDispatch dispatch) { int hresult = dispatch.TryGetTypeInfoCount(out uint typeCount); if (typeCount == 0) { // COM objects should return a type count of 0 to indicate that type info is not exposed. // Some COM objects may return a non-success HRESULT when type info is not supported, so // we only check the count and not the HRESULT in this case. return(null); } Marshal.ThrowExceptionForHR(hresult); Debug.Assert(typeCount == 1); 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); }
/// <summary> /// Look for typeinfo using IDispatch.GetTypeInfo. /// </summary> /// <param name="dispatch"></param> /// <param name="throwIfMissingExpectedTypeInfo"> /// 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</param> /// <returns></returns> internal static ComTypes.ITypeInfo GetITypeInfoFromIDispatch(IDispatch dispatch, bool throwIfMissingExpectedTypeInfo) { uint typeCount; int hresult = dispatch.TryGetTypeInfoCount(out typeCount); if ((hresult == ComHresults.E_NOTIMPL) || (hresult == ComHresults.E_NOINTERFACE)) { return(null); } else { Marshal.ThrowExceptionForHR(hresult); } Debug.Assert(typeCount <= 1); if (typeCount == 0) { return(null); } IntPtr typeInfoPtr = IntPtr.Zero; hresult = dispatch.TryGetTypeInfo(0, 0, out typeInfoPtr); if (!Utils.Succeeded(hresult)) { CheckIfMissingTypeInfoIsExpected(hresult, throwIfMissingExpectedTypeInfo); return(null); } if (typeInfoPtr == IntPtr.Zero) { // be defensive against components that return IntPtr.Zero if (throwIfMissingExpectedTypeInfo) { Marshal.ThrowExceptionForHR(ComHresults.E_FAIL); } return(null); } ComTypes.ITypeInfo typeInfo = null; try { typeInfo = Marshal.GetObjectForIUnknown(typeInfoPtr) as ComTypes.ITypeInfo; } finally { Marshal.Release(typeInfoPtr); } return(typeInfo); }