/// <summary>
        /// A basic helper for IDispatch::Invoke
        /// </summary>
        /// <param name="obj">The IDispatch object of which you want to invoke a member on</param>
        /// <param name="memberId">The dispatch ID of the member to invoke</param>
        /// <param name="invokeKind">See InvokeKind enumeration</param>
        /// <param name="args">Array of arguments to pass to the call, or null for no args</param>
        /// <remarks>TODO support DISPATCH_PROPERTYPUTREF (property-set) which requires special handling</remarks>
        /// <returns>An object representing the return value from the called routine</returns>
        public static object Invoke(IDispatch obj, int memberId, InvokeKind invokeKind, object[] args = null)
        {
            var pDispParams = PrepareDispatchArgs(args);
            var pExcepInfo  = new ComTypes.EXCEPINFO();

            int hr = obj.Invoke(memberId, ref GUID_NULL, 0, (uint)invokeKind,
                                ref pDispParams, out object pVarResult, ref pExcepInfo, out uint pErrArg);

            UnprepareDispatchArgs(pDispParams);

            if (ComHelper.HRESULT_FAILED(hr))
            {
                if ((hr == (int)KnownComHResults.DISP_E_EXCEPTION) && (ComHelper.HRESULT_FAILED(pExcepInfo.scode)))
                {
                    throw Marshal.GetExceptionForHR(pExcepInfo.scode);
                }
                throw Marshal.GetExceptionForHR(hr);
            }

            return(pVarResult);
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="outerObject">The object that needs interface requests filtered</param>
        /// <param name="queryForType">determines whether we call QueryInterface for the interface or not</param>
        /// <remarks>if the passed in outerObject is known to point to the correct vtable for the interface, then queryForType can be false</remarks>
        /// <returns>if outerObject is IntPtr.Zero, then a null wrapper, else an aggregated wrapper</returns>
        public RestrictComInterfaceByAggregation(IntPtr outerObject, bool queryForType = true)
        {
            if (queryForType)
            {
                var IID = typeof(T).GUID;
                if (ComHelper.HRESULT_FAILED(Marshal.QueryInterface(outerObject, ref IID, out _outerObject)))
                {
                    // allow null wrapping here
                    return;
                }
            }
            else
            {
                _outerObject = outerObject;
                Marshal.AddRef(_outerObject);
            }

            var aggObjPtr = Marshal.CreateAggregatedObject(_outerObject, this);

            WrappedObject = (T)Marshal.GetObjectForIUnknown(aggObjPtr); // when this CCW object gets released, it will free the aggObjInner (well, after GC)
            Marshal.Release(aggObjPtr);                                 // _wrappedObject holds a reference to this now
        }