// simply check if a COM object supports a particular COM interface // (without doing any casting by the CLR, which does much more than this under the covers) public static bool DoesComObjPtrSupportInterface <T>(IntPtr comObjPtr) { var iid = typeof(T).GUID; var hr = RdMarshal.QueryInterface(comObjPtr, ref iid, out var outInterfacePtr); if (!ComHelper.HRESULT_FAILED(hr)) { RdMarshal.Release(outInterfacePtr); return(true); } return(false); }
private void TraceRelease(int rcwCount, ref bool addRef) { if (!addRef) { // Temporarily add a ref so that we can safely call IUnknown::Release // to report the ref count in the log. RdMarshal.AddRef(_pUnk); } var refCount = RdMarshal.Release(_pUnk); Debug.Print($"ComPointer:: Disposed: _pUnk: {RdMarshal.FormatPtr(_pUnk)} _interface: {typeof(TComInterface).Name} - {Interface.GetHashCode()} addRef: {_addRef} rcwCount: {rcwCount} refCount: {refCount}"); addRef = false; }
private void ReleaseUnmanagedResources() { if (_disposed) { return; } var rcwCount = RdMarshal.ReleaseComObject(Interface); var addRef = _addRef; TraceRelease(rcwCount, ref addRef); if (addRef) { RdMarshal.Release(_pUnk); } _disposed = true; }
void ComTypes.ITypeInfo.CreateInstance(object pUnkOuter, ref Guid riid, out object ppvObj) { // initialize out parameters ppvObj = default; using (var outPpvObj = AddressableVariables.CreateObjectPtr <object>()) { var unkOuter = RdMarshal.GetIUnknownForObject(pUnkOuter); var hr = _this_Internal.CreateInstance(unkOuter, riid, outPpvObj.Address); RdMarshal.Release(unkOuter); if (ComHelper.HRESULT_FAILED(hr)) { HandleBadHRESULT(hr); } ppvObj = outPpvObj.Value; } }
/// <summary> /// Takes a COM object, and reads the unmanaged memory given by its pointer, allowing us to read internal fields /// </summary> /// <typeparam name="T">the type of structure to return</typeparam> /// <param name="comObj">the COM object</param> /// <returns>the requested structure T</returns> public static T ReadComObjectStructure <T>(object comObj) { // Reads a COM object as a structure to copy its internal fields if (!RdMarshal.IsComObject(comObj)) { throw new ArgumentException("Expected a COM object"); } var referencesPtr = RdMarshal.GetIUnknownForObjectInContext(comObj); if (referencesPtr == IntPtr.Zero) { throw new InvalidOperationException("Cannot access the TypeLib API from this thread. TypeLib API must be accessed from the main thread."); } var retVal = ReadStructureSafe <T>(referencesPtr); RdMarshal.Release(referencesPtr); return(retVal); }
/// <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(RdMarshal.QueryInterface(outerObject, ref iid, out _outerObject))) { // allow null wrapping here return; } } else { _outerObject = outerObject; RdMarshal.AddRef(_outerObject); } var clrAggregator = RdMarshal.CreateAggregatedObject(_outerObject, this); WrappedObject = (T)RdMarshal.GetObjectForIUnknown(clrAggregator); // when this CCW object gets released, it will free the aggObjInner (well, after GC) RdMarshal.Release(clrAggregator); // _wrappedObject holds a reference to this now }
protected virtual void Dispose(bool disposing) { if (_isDisposed || !disposing) { return; } _isDisposed = true; if (WrappedObject != null) { RdMarshal.ReleaseComObject(WrappedObject); } if (_outerObject != IntPtr.Zero) { RdMarshal.Release(_outerObject); // dont set _outerObject to IntPtr.Zero here, as GetInterface() can still be called by the outer RCW // if it is still alive. For example, if ExtractWrappedObject was used and the outer object hasn't yet // been released with ReleaseComObject. In that circumstance _outerObject will still be a valid pointer // due to the internally held reference, and so GetInterface() calls past this point are still OK. } }