// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Reflection; using System.Runtime.InteropServices; using SharpGen.Runtime.Diagnostics; namespace SharpGen.Runtime { /// /// Root IUnknown class to interop with COM object /// public partial class ComObject { /// /// Initializes a new instance of the class from a IUnknown object. /// /// Reference to a IUnknown object public ComObject(object iunknownObject) { NativePointer = Marshal.GetIUnknownForObject(iunknownObject); } /// /// Initializes a new instance of the class. /// protected ComObject() { } /// /// Query instance for a particular COM GUID/interface support. /// /// GUID query interface /// If this object doesn't support the interface /// ms682521 /// IUnknown::QueryInterface /// IUnknown::QueryInterface public virtual IntPtr QueryInterfaceOrNull(Guid guid) { var pointer = IntPtr.Zero; QueryInterface(guid, out pointer); return pointer; } /// /// Compares 2 COM objects and return true if the native pointer is the same. /// /// The left. /// The right. /// true if the native pointer is the same, false otherwise public static bool EqualsComObject(T left, T right) where T : ComObject { if (Equals(left, right)) { return true; } if (left == null || right == null) { return false; } return (left.NativePointer == right.NativePointer); } /// /// Query this instance for a particular COM interface support. /// ///The type of the COM interface to query ///An instance of the queried interface /// If this object doesn't support the interface /// ms682521 /// IUnknown::QueryInterface /// IUnknown::QueryInterface public virtual T QueryInterface() where T : ComObject { IntPtr parentPtr; var result = this.QueryInterface(typeof(T).GetTypeInfo().GUID, out parentPtr); result.CheckError(); return FromPointer(parentPtr); } /// /// Queries a managed object for a particular COM interface support (This method is a shortcut to ) /// ///The type of the COM interface to query /// The managed COM object. ///An instance of the queried interface /// ms682521 /// IUnknown::QueryInterface /// IUnknown::QueryInterface public static T As(object comObject) where T : ComObject { using (var tempObject = new ComObject(Marshal.GetIUnknownForObject(comObject))) { return tempObject.QueryInterface(); } } /// /// Queries a managed object for a particular COM interface support (This method is a shortcut to ) /// ///The type of the COM interface to query /// The managed COM object. ///An instance of the queried interface /// ms682521 /// IUnknown::QueryInterface /// IUnknown::QueryInterface public static T As(IntPtr iunknownPtr) where T : ComObject { using (var tempObject = new ComObject(iunknownPtr)) { return tempObject.QueryInterface(); } } /// /// Queries a managed object for a particular COM interface support. /// ///The type of the COM interface to query /// The managed COM object. ///An instance of the queried interface /// ms682521 /// IUnknown::QueryInterface /// IUnknown::QueryInterface public static T QueryInterface(object comObject) where T : ComObject { using (var tempObject = new ComObject(Marshal.GetIUnknownForObject(comObject))) { return tempObject.QueryInterface(); } } /// /// Queries a managed object for a particular COM interface support. /// ///The type of the COM interface to query /// A pointer to a COM object. ///An instance of the queried interface /// ms682521 /// IUnknown::QueryInterface /// IUnknown::QueryInterface public static T QueryInterfaceOrNull(IntPtr comPointer) where T : ComObject { if (comPointer == IntPtr.Zero) { return null; } var guid = typeof(T).GetTypeInfo().GUID; IntPtr pointerT; var result = (Result)Marshal.QueryInterface(comPointer, ref guid, out pointerT); return (result.Failure) ? null : FromPointer(pointerT); } /// /// Query Interface for a particular interface support. /// ///An instance of the queried interface or null if it is not supported /// /// ms682521 /// IUnknown::QueryInterface /// IUnknown::QueryInterface public virtual T QueryInterfaceOrNull() where T : ComObject { return FromPointer(QueryInterfaceOrNull(typeof(T).GetTypeInfo().GUID)); } /// /// Query Interface for a particular interface support and attach to the given instance. /// /// /// protected void QueryInterfaceFrom(T fromObject) where T : ComObject { IntPtr parentPtr; fromObject.QueryInterface(this.GetType().GetTypeInfo().GUID, out parentPtr); NativePointer = parentPtr; } /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. /// ms682317 /// IUnknown::Release /// IUnknown::Release protected unsafe override void Dispose(bool disposing) { // Only dispose non-zero object if (NativePointer != IntPtr.Zero) { // If object is disposed by the finalizer, emits a warning if(!disposing && Configuration.EnableTrackingReleaseOnFinalizer) { if(!Configuration.EnableReleaseOnFinalizer) { var objectReference = ObjectTracker.Find(this); LogMemoryLeakWarning?.Invoke(string.Format("Warning: Live ComObject [0x{0:X}], potential memory leak: {1}", NativePointer.ToInt64(), objectReference)); } } // Release the object if (disposing || Configuration.EnableReleaseOnFinalizer) ((IUnknown)this).Release(); // Untrack the object if (Configuration.EnableObjectTracking) ObjectTracker.UnTrack(this); // Set pointer to null (using protected members in order to avoid NativePointerUpdat* callbacks. _nativePointer = (void*)0; } base.Dispose(disposing); } } }